Оптимизация SQL-запроса с огромным предложением where

Я работаю над системой (с Laravel), где пользователи могут заполнить несколько фильтров, чтобы получить нужные им данные. Данные не подготавливаются в реальном времени, после установки фильтров задание помещается в очередь, а после завершения запроса создается файл CSV. Затем пользователь получает электронное письмо с файлом, который был создан, чтобы он мог его скачать.

Я видел некоторые ошибки в заданиях, когда обработка одного задания занимала более 30 минут, и когда я проверил, я увидел, что некоторые пользователи создали фильтр с более чем 600 значениями.

Значения этого фильтра переводятся так:

SELECT filed1, 
       field2, 
       field6 
FROM   table 
       INNER JOIN table2 
               ON table.id = table2.cid 
/* this is how we try not to give same data to the users again so we used NOT IN */ 
WHERE  table.id NOT IN(SELECT data_id 
                       FROM   data_access 
                       WHERE  data_user = 26) 
       AND ( /* this bit is auto populated with the filter values */ 
           table2.filed_a = 'text a' 
            OR table2.filed_a = 'text b' 
            OR table2.filed_a = 'text c' ) 

Что ж, я не ожидал, что пользователи будут сходить с ума и точно настраиваться с помощью огромного набора фильтров. Для них это нормально, но им нужно решение, чтобы сделать этот запрос быстрее.

Один из способов - создать на лету временную таблицу со значениями фильтра и скрыть запрос для INNER JOIN, но не уверен, что это повысит производительность. Кроме того, учитывая, что в обычном режиме системе потребуется создать не менее 40 временных таблиц и затем удалить их. Станет ли это еще одной проблемой в долгосрочной перспективе?

Я хотел бы услышать любые другие предложения, которые могут помочь мне решить эту проблему, кроме метода временной таблицы.

Вы проверили план EXPLAIN? Я спрашиваю об этом, потому что подзапрос в WHERE - это нет, коррелированный с внешним запросом, а это означает, что MySQL, вероятно, может запустить его один раз и кэшировать результаты. Так что я не уверен, что это будет вашим самым большим узким местом.

Tim Biegeleisen 30.12.2018 15:34

Действительно, то, что подзапрос в выражении NOT IN не коррелирован, мне кажется очень подозрительным, особенно в свете связанного комментария.

John Bollinger 30.12.2018 15:39

вы уже пытаетесь изменить WHERE table.id NOT IN (подзапрос) с LEFT JOIN data_access ON data_access.data_id = table.id ГДЕ data_access.data_id IS NULL?

Magicianred 30.12.2018 15:41
Освоение архитектуры микросервисов с 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
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2
3
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы посоветовал написать такой запрос:

SELECT ?.filed1, ?.field2, ?.field6  -- qualify column names (but no effect on performance)
FROM table t JOIN
     table2 t2
     ON t.id = t2.cid 

WHERE NOT EXISTS (SELECT 1
                  FROM data_access da
                  WHERE t.id = da.data_id AND da.data_user = 26
                 ) AND
     t2.filed_a IN ('text a', 'text b', 'text c') ;

Тогда я бы порекомендовал индексы. Вероятно:

  • table2(filed_a, cid)
  • table1(id) (может не понадобиться, если id уже является первичным ключом)
  • data_access(data_id, data_user)

Вы можете проверить это как свой собственный запрос. Я не знаю, как заставить Laravel создать это (при условии, что это соответствует вашим целям производительности).

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