Laravel с медленным запросом subSelect (MySQL)

При выполнении запроса на веб-сайте (запрос 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">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;</td></tr></tbody></table>
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
0
194
2

Ответы 2

Вы можете удалить эти запросы как часть этого большого запроса

(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 

поскольку они не слишком способствуют результату. Добавьте эти два столбца отдельно.

Внутри метода whereIn около 250 чисел, иногда больше. Таким образом, я должен вручную сопоставить все. Не уверен, что это будет быстрее.

Tim 23.01.2019 09:40

Прежде всего попробуйте посмотреть, как выглядит ваш план запроса. Вы можете проверить это с помощью команды 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 не строит запрос быстро. Это тоже проверим. Я обновил вопрос.

Tim 23.01.2019 09:49

Возможно, вы захотите попробовать добавить индексы в g_id, кроватку для таблицы lm_images...

David Heremans 24.01.2019 14:43

Другие вопросы по теме