При выполнении запроса на веб-сайте (запрос ajax, Laravel 5.7) он выполняется на 99% быстро (где-то около 800 мс), но в 1% общее время выполнения запроса может достигать 50 секунд.
В чем проблема такого поведения, есть ли какое-то кеширование? Кроме того, нужно ли что-то оптимизировать?
Вот запрос (@numbers -> здесь идет массив до 250 чисел):
SELECT
var.g_id,
var.title,
lm_object.title AS ht_title,
lm_object.image_checked_at,
var.cot,
var.cca,
var.cot_cca,
var.rating,
var.lm_object_id AS var_id,
lm_object.id AS hot_id,
(SELECT link FROM lm_images WHERE typ = 1 AND thumb = 1 AND
( id = var.id OR cot _cca = var.cot _cca ) LIMIT 1 ) AS th,
(SELECT link FROM lm_images WHERE typ = 2 AND thumb = 1 AND
( id = var.id OR cot_cca = var.cot _cca ) LIMIT 1 ) AS th_1
FROM lm_object
INNER JOIN lm_object_sar AS var ON lm_ object.id = var.lm_object_id
WHERE
var.id IN ( @numbers...)
AND lm_object.deleted_at IS NULL
ОБЪЯСНИТЕ ВЫБРАТЬ:
<table width = "973" border = "1"><thead><tr><td width = "88"><p><strong>id</strong></p></td><td width = "88"><p><strong>select_type</strong></p></td><td width = "89"><p><strong>table</strong></p></td><td width = "88"><p><strong>type</strong></p></td><td width = "109"><p><strong>possible_keys</strong></p></td><td width = "68"><p><strong>key</strong></p></td><td width = "88"><p><strong>key_len</strong></p></td><td width = "88"><p><strong>ref</strong></p></td><td width = "89"><p><strong>rows</strong></p></td><td width = "88"><p><strong>Extra</strong></p></td><td width = "89"> </td></tr></thead><tbody><tr><td width = "88"><p>1</p></td><td width = "88"><p>PRIMARY</p></td><td width = "89"><p>var</p></td><td width = "88"><p>range</p></td><td width = "109"><p>g_id_cot_cca,g_id,lm_objects_id</p></td><td width = "68"><p>g_id_cot_cca</p></td><td width = "88"><p>5</p></td><td width = "88"><p><em>NULL</em></p></td><td width = "89"><p>246</p></td><td width = "88"><p>Using index condition; Using where</p></td><td width = "89"> </td></tr><tr><td width = "88"><p>1</p></td><td width = "88"><p>PRIMARY</p></td><td width = "89"><p>lm_objects</p></td><td width = "88"><p>eq_ref</p></td><td width = "109"><p>PRIMARY</p></td><td width = "68"><p>PRIMARY</p></td><td width = "88"><p>4</p></td><td width = "88"><p>mydb.var.lm_objects_id</p></td><td width = "89"><p>1</p></td><td width = "88"><p>Using where</p></td><td width = "89"> </td></tr><tr><td width = "88"><p>3</p></td><td width = "88"><p>DEPENDENT SUBQUERY</p></td><td width = "89"><p>lm_images</p></td><td width = "88"><p>ALL</p></td><td width = "109"><p>g_id,cot</p></td><td width = "68"><p><em>NULL</em></p></td><td width = "88"><p><em>NULL</em></p></td><td width = "88"><p><em>NULL</em></p></td><td width = "89"><p>119603</p></td><td width = "88"><p>Using where</p></td><td width = "89"> </td></tr><tr><td width = "88"><p>2</p></td><td width = "88"><p>DEPENDENT SUBQUERY</p></td><td width = "89"><p>lm_images</p></td><td width = "88"><p>ALL</p></td><td width = "109"><p>g_id,cot</p></td><td width = "68"><p><em>NULL</em></p></td><td width = "88"><p><em>NULL</em></p></td><td width = "88"><p><em>NULL</em></p></td><td width = "89"><p>119603</p></td><td width = "88"><p>Using where</p></td><td width = "89"> </td></tr></tbody></table>





Вы можете удалить эти запросы как часть этого большого запроса
(SELECT link FROM lm_images WHERE typ = 1 AND thumb = 1 AND
( id = var.id OR cot _cca = var.cot _cca ) LIMIT 1 ) AS th,
(SELECT link FROM lm_images WHERE typ = 2 AND thumb = 1 AND
( id = var.id OR cot_cca = var.cot _cca ) LIMIT 1 ) AS th_1
поскольку они не слишком способствуют результату. Добавьте эти два столбца отдельно.
Прежде всего попробуйте посмотреть, как выглядит ваш план запроса. Вы можете проверить это с помощью команды EXPLAIN. Он покажет вам, где вы можете повысить производительность, добавляя индексы там, где это необходимо.
Во-вторых, я всегда предпочитаю избегать подзапросов. Вы можете переписать приведенный выше запрос, используя дополнительные соединения для внешнего выбора, и отфильтровать их, как только сможете. Вы можете попробовать следующее и посмотреть, как это сравнивается:
SELECT *
FROM lm_object
INNER JOIN lm_object_sar var
ON lm_object.id = var.lm_object_id
LEFT JOIN lm_images img1
ON img1.typ = 1
AND img1.thumb = 1
AND (
img1.id = var.id
OR img1.cot_cca = var.cot_cca
)
LEFT JOIN lm_images img2
ON img2.typ = 2
AND img2.thumb = 1
AND (
img2.id = var.id
OR img2.cot_cca = var.cot_cca
)
WHERE var.id IN (@numbers...)
AND lm_object.deleted_at IS NULL
Обратите внимание, что вышеприведенное вернет несколько строк, если у вас может быть больше записей img1 и img2; Я вижу, вы применили LIMIT 1, что заставляет меня думать, что благодаря этим фильтрам у вас может быть больше строк.
Если это так, вероятно, лучше просто запросить их отдельно в вашем коде, чем пытаться втиснуть их в один «большой» запрос.
Кроме того, рассмотрите возможность мониторинга вашего приложения с помощью такой службы, как newRelic; это может дать вам представление о том, что именно вызвало эту 50-секундную задержку. Вы уверены, что это ваш запрос к базе данных?
Должно быть только по одному изображению каждого типа, ограничение было просто даром. Что касается запроса, я записал время до запроса laravel и после него, поэтому также есть вероятность, что laravel не строит запрос быстро. Это тоже проверим. Я обновил вопрос.
Возможно, вы захотите попробовать добавить индексы в g_id, кроватку для таблицы lm_images...
Внутри метода whereIn около 250 чисел, иногда больше. Таким образом, я должен вручную сопоставить все. Не уверен, что это будет быстрее.