Как ускорить процесс выполнения запроса в БД?

Привет всем! В таблице есть почти 500к записей. Всего три столбца: id, url, data.
В столбце data хранится json. Каждый день выполняется запрос, который создает массив из тоже примерно 500к записей и потом циклом я проверяю есть ли в бд запись с таким url и если есть, то присваивает полю data единицу, если такого урл нет в базе, то создает новую запись.
Это всё работает ну очень долго, в районе 2х часов.
Прикрепляю код:
foreach ($data as $key => $item) {
	$res = $mysqli->query("SELECT * FROM `name` WHERE url = '".$item['url']."'");
	if($res->num_rows){
		$mysqli->query("UPDATE `name` SET data = '1' WHERE url = '".$item['url']."'");
	} else{
		$mysqli->query("INSERT INTO `name` (url, data) VALUES ('".$item['url']."','".$item['price']."')");
	}
}
  • Вопрос задан
  • 443 просмотра
Решения вопроса 1
@Quieteroks
php программист
Какой тип таблиц используете?
Если InnoDB, то при частых обновления и вставках, в больших таблицах, вы всегда будете получать подобный результат. Самый простой способ в этом случае ускорить, перенести таблицу в MyISAM.

Второе, это подготавливайте инсерты пачками. Даже если в строку вы соберете более 100 записей и разом их запихнете, получится быстрее, чем каждый раз выполнять этот запрос.

И третье. Обновляйте по id, зачем же вы ищете, потом опять ищете для обновления по url. Строчку вы уже получили, можно так считать. Используйте сразу id. И вообще запрос упростите, пишите SELECT `id` FROM... Другие данные Вам не нужны. И ускорите получение и ускорите обновление.

Кстати. Четвертое. Если вы все равно всем записям меняете поле data на 1, можно так же обновление сделать пачкой. Собирайте id найденных записей и обновляйте через UPDATE `name` SET `data` = '1' WHERE `id` IN (1,2,5,7,88,123).
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
@RidgeA
Какая длинна значений url?
Можно сделать уникальный индекс по полю url и потом одним запросом обновить все
https://dev.mysql.com/doc/refman/5.7/en/insert-on-...
Только про json я не понял
Ответ написан
Therapyx
@Therapyx
Data Science
ко всему, что написали сверху - сделайте индексацию нужных полей. Вы про это ничего не написали, а индексация как правило очень и очень серьезно повышает производительность бинарного поиска, вставки и удалений.
Ответ написан
Комментировать
@serikamanco Автор вопроса
Спасибо всем. Создал индексы, добавил поле offer_id, которое гораздо короче, чем урл и буду пробовать!
Ответ написан
Комментировать
2ball
@2ball
Хардкор кодер
Дополнительно перейдите на PDO, используйте PREPARED_STATEMENTS, отключите буферизацию и эмуляцию подготовленных запросов в PDO. PHP очень сильно выжирает ресурсы по эмуляции. А с подготовленными запросами MySQL не будет каждый раз парсить сам запрос. Достаточно биндить значения и отправлять.
Ответ написан
Комментировать
Fragster
@Fragster
помогло? отметь решением!
Не может 500к записей в таких запросах работать больше 2 часов. при 500 к записей даже при тэйбл скан это будет в диапазоне минут (размер строки не более пол килобайта, соответственно, 250 мегабайт на таблицу, что примерно 10-30 секунд на 5400 хдд на запрос селект и апдейт). Ну, или машина совсем старая или виртуалка, ужатая по ресурсам.
В данном случае посоветую сделать таблицу с индексом по хэшу урл (для ограничения длины колонки с индексом) и проверять его. В зависимости от бизнес логики может быть можно сократить запрос до insert .. on duplicate key update
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы