2016-03-02 4 views
0

У меня есть следующие таблицы в MySQL:группы MySQL по запросу с оптимизацией подвыборки

CREATE TABLE `events` (
    `pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `time_stamp` bigint(20) unsigned NOT NULL, 
    `event_type` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, 
    `value_type` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 
    `value_count` bigint(20) DEFAULT NULL, 
    `alarm_status` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 
    `alarm_severity` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 
    PRIMARY KEY (`pv_name`,`time_stamp`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED; 

CREATE TEMPORARY TABLE `matching_pv_names` (
    `pv_name` varchar(60) NOT NULL, 
    PRIMARY KEY (`pv_name`) 
) ENGINE=Memory DEFAULT CHARSET=latin1; 

Таблица matching_pv_names содержит подмножество уникальных events.pv_name значений.

Следующий запрос выполняется с помощью «свободного индекса сканирования» оптимизации:

SELECT events.pv_name, MAX(events.time_stamp) AS time_stamp 
FROM events 
WHERE events.time_stamp <= time_stamp_in 
GROUP BY events.pv_name; 

Можно ли улучшить время этого запроса, ограничивая events.pv_name значения для тех, кто в matching_pv_names таблицы не теряя «свободно оптимизация индекса?

+0

что-то странное. Откуда находится поле «time_stamp_in»? – Kordi

+0

time_stamp_in скорее всего является входным значением. –

+0

time_stamp_in - переменная, переданная в хранимую процедуру, в которой выполняется запрос. – Patrick

ответ

0

Попробуйте выполнить одну из нижеперечисленных запросов, чтобы ограничить вывод на соответствие найденным значениям в matching_pv_names.

Запрос 1:

SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp 
FROM events e 
INNER JOIN matching_pv_names pv ON e.pv_name = pv.pv_name 
WHERE e.time_stamp <= time_stamp_in 
GROUP BY e.pv_name; 

Запрос 2:

SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp 
FROM events e 
WHERE e.time_stamp <= time_stamp_in 
AND EXISTS (select 1 from matching_pv_names pv WHERE e.pv_name = pv.pv_name) 
GROUP BY e.pv_name; 

Процитирую manual здесь, так как я думаю, что это относится к вашему делу (жирный курсив мой):

Если предложение WHERE содержит предикаты диапазона (...), развертка индекса сканирования просматривает первый ключ каждой группы , который удовлетворяет ies условия диапазона, и снова считывает наименьшее возможное количество ключей. Это возможно при следующих условиях:

Запрос по одной таблице.

Зная это, я считаю, что запрос 1 не сможет использовать развертку индекса, но, возможно, второй запрос может это сделать. Если это еще не так, вы также можете попробовать третий предложенный метод, который использует производную таблицу.

Запрос 3:

SELECT e.* 
FROM (
    SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp 
    FROM events e 
    WHERE e.time_stamp <= time_stamp_in 
    GROUP BY e.pv_name 
) e 
INNER JOIN matching_pv_names pv ON e.pv_name = pv.pv_name; 
+0

Спасибо, я попробую. – Patrick

+0

Query2 действительно может работать, и это хорошая идея. Я думаю, что другой запрос не соответствует критериям для быстрого сканирования индекса. см. критерии по адресу http://dev.mysql.com/doc/refman/5.7/en/group-by-optimization.html. – Kordi

+0

После тестирования выяснилось, что первые два запроса не используют развертку индекса и занимают больше времени. Третий использует развернутое сканирование индекса, но, похоже, оно ограничивает имена pv после того, как группа выполнена? – Patrick

0

Ваш запрос очень эффективным. Вы можете «доказать» это, делая это:

FLUSH STATUS; 
SELECT ...; 
SHOW SESSION STATUS LIKE 'Handler%'; 

Большинства номера относится к «строки прикоснулись», либо в индексе или в данных. Вы увидите очень низкие цифры. Если самый большой из них - о количестве возвращаемых строк, это очень хорошо. (Я пробовал подобный запрос и получил около 2х, я не знаю, почему.)

При том, что несколько строк прикоснулся затем либо

  • Выведение строки накроет время выполнения. Итак, кто заботится об эффективности; или
  • Вы были связаны с I/O из-за перескока по индексу (фактически, таблица в вашем случае). Запустите его второй раз; это будет быстро из-за кеширования.

Единственный способ ускорить перепрыгнуть, чтобы каким-то образом переместить нужные строки рядом друг с другом. Это кажется необоснованным для этого вопроса.

Что касается игр с другим столом - возможно. Будет ли JOIN значительно уменьшать количество событий, на которые нужно смотреть? Тогда Может быть. В противном случае я говорю: «очень эффективный запрос не ускорится, добавив сложности».

Смежные вопросы