MySQL - Представления - Супер медленный запрос - PullRequest
9 голосов
/ 24 сентября 2011

Это странно. Я пытаюсь использовать Views в MySQL (я достаточно новичок в MySQL с большим опытом работы с Sybase и SQL Server). В любом случае, в этом новом проекте мы используем MySQL, так как он, кажется, имеет хорошую производительность. Однако, чтобы упростить запросы к веб-интерфейсу, мы решили создать несколько представлений, все работают хорошо, но на их выполнение уходит вечность.

Представления очень просты, просто выберите операторы (в этих таблицах несколько миллионов строк) . Скажем, например, этот запрос:

SELECT CAST(classifier_results.msgDate as DATE) AS mdate
       ,classifier_results.objClass AS objClass
       ,COUNT(classifier_results.objClass) AS obj
       ,classifier_results.subjClass AS subjClass
       ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

При запуске в обычном режиме для возврата результата требуется около 1,5 секунд.

Однако, когда этот запрос помещается в представление (как есть) - т.е.

CREATE VIEW  V1a_sentiment_AI_current AS    
SELECT CAST(classifier_results.msgDate as DATE) AS mdate
       ,classifier_results.objClass AS objClass
       ,COUNT(classifier_results.objClass) AS obj
       ,classifier_results.subjClass AS subjClass
       ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

Запрос занимает в 10 раз больше времени (22-30 секунд). Поэтому я думаю, что, возможно, есть какая-то оптимизация или кэширование запросов, которые не работают с Views, или, может быть, есть некоторые настройки, которые мы пропустили в конфигурации MySQL. Но есть ли способ ускорить это представление, так что это просто полезный заполнитель для этого запроса?

Запуск EXPLAIN для двух запросов: Нормальный выбор дает:

1, SIMPLE, classifier_results, ALL, idx_date,,,, 594845, Использование где; Используя временные; Использование сортировки файлов

Выбор представления дает:

1, ПЕРВИЧНЫЙ,, ВСЕ,,,,, 100,
2, ПОЛУЧЕНО, classifier_results, ALL, idx_date,,,, 594845, Использование где; Используя временные; Использование файловой сортировки

Ответы [ 3 ]

1 голос
/ 15 апреля 2014

Это действительно распространенная проблема.Это может быть очень трудно написать СУХОЙ, повторно используемый SQL.Однако я нашел обходной путь.

Во-первых, как уже отмечали другие, вы можете и должны использовать VIEW, чтобы делать это везде, где это возможно, используя набор ALGORITHM = MERGE, так что любые запросы, использующие их, оптимизируютсяв объединенном предложении SQL оператора where вместо оценки VIEW для всего представления, которое может быть катастрофически большим.

В этом случае, поскольку вы не можете использовать MERGE из-за аспекта group / count, вы можете попробовать использовать хранимую процедуру, которая создает временную таблицу сеансов в качестве обходного пути.

Этот метод позволяет вам писать запросы многократного использования, к которым можно обращаться из кода промежуточного программного обеспечения / фреймворка и вызывать из других хранимых процедур, так что вы можете хранить код в содержании, поддерживаемом и повторно используемом.Вы заранее знаете, что запрос будет отфильтрован при определенных условиях, поместите их в хранимую процедуру.(Может быть более эффективно постфильтровать набор данных или их комбинацию - это зависит от того, как вы используете данные и какие общие наборы необходимы).

CREATE PROCEDURE sp_create_tmp_V1a_sentiment_AI_current(parm1, parm2 etc)
BEGIN

  drop temporary table if exists tmp_V1a_sentiment_AI_current;

  create temporary table tmp_V1a_sentiment_AI_current
  as
  SELECT CAST(classifier_results.msgDate as DATE) AS mdate
         ,classifier_results.objClass AS objClass
         ,COUNT(classifier_results.objClass) AS obj
         ,classifier_results.subjClass AS subjClass
         ,COUNT(classifier_results.subjClass) AS subj 
  FROM classifier_results 
  WHERE (classifier_results.msgDate >= (curdate() - 20)) 
  -- and/or other filters on parm1, parm2 passed in
  GROUP BY 
    CAST(classifier_results.msgDate as DATE)
    ,classifier_results.objClass
    ,classifier_results.subjClass 
  ORDER BY classifier_results.msgDate DESC;

END;

Теперь, когда вам нужно работатьс этими данными вы вызываете процедуру и затем либо выбираете результат (возможно, с дополнительными параметрами предложения where), либо присоединяетесь к нему в любом другом запросе.

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

Надеюсь, это полезно.

1 голос
/ 24 сентября 2011

Попробуйте заново создать представление, используя это:

CREATE ALGORITHM = MERGE VIEW `V1a_sentiment_AI_current` AS    
SELECT CAST(classifier_results.msgDate as DATE) AS mdate
   ,classifier_results.objClass AS objClass
   ,COUNT(classifier_results.objClass) AS obj
   ,classifier_results.subjClass AS subjClass
   ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

Более подробную информацию об алгоритмах обработки представления MySQL можно найти здесь .

0 голосов
/ 09 апреля 2013

MERGE не может использоваться здесь из-за агрегатов count () в списке выбора;в этих случаях может быть полезно указать TEMPTABLE, чтобы избавить двигатель от необходимости выбирать между ними.После того, как я решил, какой алгоритм использовать, я посмотрю на план EXPLAIN и попытаюсь добавить подсказку индекса или найти отсутствующий индекс.

...