Оптимизация SQL-запроса с огромным предложением where - PullRequest
0 голосов
/ 30 декабря 2018

Я работаю в системе (с 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 временных таблиц и затем удалить их.Не станет ли это проблемой в долгосрочной перспективе?

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

1 Ответ

0 голосов
/ 30 декабря 2018

Я бы предложил написать запрос следующим образом:

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 производить это (при условии, что это соответствует вашим целям производительности).

...