Заказ MYSQL настаивает на использовании сортировки файлов - PullRequest
0 голосов
/ 05 марта 2010

Мне нужно оптимизировать запрос MYSQL, выполняя заказ.Независимо от того, что я делаю, mysql заканчивает тем, что делал файловую сортировку вместо использования индекса.

Вот моя таблица ddl ... (Да, в этом случае столбцы DAYSTAMP и TIMESTAMP в точности совпадают).

CREATE TABLE DB_PROBE.TBL_PROBE_DAILY ( 
  DAYSTAMP date NOT NULL, 
  TIMESTAMP date NOT NULL, 
  SOURCE_ADDR varchar(64) NOT NULL, 
  SOURCE_PORT int(10) NOT NULL, 
  DEST_ADDR varchar(64) NOT NULL, 
  DEST_PORT int(10) NOT NULL, 
  PACKET_COUNT int(20) NOT NULL, 
  BYTES int(20) NOT NULL, 
UNIQUE KEY IDX_TBL_PROBE_DAILY_05 (DAYSTAMP,SOURCE_ADDR(16),SOURCE_PORT,
                                   DEST_ADDR(16),DEST_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_01 (SOURCE_ADDR(16),TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_02 (DEST_ADDR(16),TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_03 (SOURCE_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_04 (DEST_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_06 (DAYSTAMP,TIMESTAMP,BYTES) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1  

/*!50100 PARTITION BY RANGE (to_days(DAYSTAMP)) 

(PARTITION TBL_PROBE_DAILY_P20100303 VALUES LESS THAN (734200) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100304 VALUES LESS THAN (734201) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100305 VALUES LESS THAN (734202) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100306 VALUES LESS THAN (734203) ENGINE = InnoDB) */;

Разделы выполняются ежедневно, и я добавил IDX_TBL_PROBE_DAILY_06 специально для запроса, который я пытаюсь получить, а именно:

select SOURCE_ADDR as 'Source_IP',    
       SOURCE_PORT as 'Source_Port', 
       DEST_ADDR as 'Destination_IP', 
       DEST_PORT as 'Destination_Port', 
       BYTES 
from TBL_PROBE_DAILY 
where DAYSTAMP >= '2010-03-04' and DAYSTAMP <= '2010-03-04' 
  and TIMESTAMP >= FROM_UNIXTIME(1267653600) and TIMESTAMP <= FROM_UNIXTIME(1267687228) 
order by bytes desc limit 20;

План объяснения следующий:

+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+ | id | select_type | table |
partitions | type | possible_keys |
key | key_len | ref | rows | Extra |
+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+ | 1 | SIMPLE | TBL_PROBE_DAILY |
TBL_PROBE_DAILY_P20100304 | range |
IDX_TBL_PROBE_DAILY_05,IDX_TBL_PROBE_DAILY_06 | IDX_TBL_PROBE_DAILY_05 | 3 | NULL |
216920 | Using where; Using filesort |
+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+

Я также пытался использовать FORCE INDEX (IDX_TBL_PROBE_DAILY_06), и в этом случае он успешно использует IDX_06 для удовлетворения ограничений where, но все еще выполняет сортировку файлов: (

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

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

Ответы [ 4 ]

2 голосов
/ 05 марта 2010

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

В любом случае, если я добавлю индекс

create index IDX_TBL_PROBE_DAILY_07 on TBL_PROBE_DAILY(BYTES,DAYSTAMP)   

затем mysql поддерживает IDX07 (даже без индекса принудительного ввода) и выполняет сортировку индекса вместо сортировки файла.

0 голосов
/ 08 февраля 2013

Подкачка сработала, потому что

Чтобы отсортировать или сгруппировать таблицу, если сортировка или группировка выполняется по крайнему левому префиксу используемого ключа (например, ORDER BY key_part1, key_part2). Если после всех ключевых частей следует DESC, ключ читается в обратном порядке. См. Раздел 8.3.1.11, «Оптимизация ORDER BY» и Раздел 8.3.1.12, «Оптимизация GROUP BY».

0 голосов
/ 01 ноября 2010

Использование открытого равенства в том, где всегда форсирует сортировку файлов. Проще говоря, открытый конец <или> заставляет MySQL получать строки и упорядочивать их, чтобы исключить те, которые не соответствуют вашему запросу. Если логически этот запрос может быть изменен на диапазон (между отметкой времени X и отметкой времени Y), ТОГДА MySQL может использовать эти выходные значения, чтобы получить результаты непосредственно из индекса, а затем либо файловую сортировку, если вы все еще хотите отсортировать возврат, или нет, если вы хотите только сопоставьте значения

0 голосов
/ 05 марта 2010

Я не мог прочитать определение. Вот это отформатировано:

CREATE TABLE DB_PROBE.TBL_PROBE_DAILY ( 
  DAYSTAMP date NOT NULL, 
  TIMESTAMP date NOT NULL, 
  SOURCE_ADDR varchar(64) NOT NULL, 
  SOURCE_PORT int(10) NOT NULL, 
  DEST_ADDR varchar(64) NOT NULL, 
  DEST_PORT int(10) NOT NULL, 
  PACKET_COUNT int(20) NOT NULL, 
  BYTES int(20) NOT NULL, 
UNIQUE KEY IDX_TBL_PROBE_DAILY_05 (DAYSTAMP,SOURCE_ADDR(16),SOURCE_PORT,
                                   DEST_ADDR(16),DEST_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_01 (SOURCE_ADDR(16),TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_02 (DEST_ADDR(16),TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_03 (SOURCE_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_04 (DEST_PORT,TIMESTAMP), 
KEY IDX_TBL_PROBE_DAILY_06 (DAYSTAMP,TIMESTAMP,BYTES) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1  

/*!50100 PARTITION BY RANGE (to_days(DAYSTAMP)) 

(PARTITION TBL_PROBE_DAILY_P20100303 VALUES LESS THAN (734200) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100304 VALUES LESS THAN (734201) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100305 VALUES LESS THAN (734202) ENGINE = InnoDB, 
 PARTITION TBL_PROBE_DAILY_P20100306 VALUES LESS THAN (734203) ENGINE = InnoDB) */;

Запрос:

select SOURCE_ADDR as 'Source_IP',    
       SOURCE_PORT as 'Source_Port', 
       DEST_ADDR as 'Destination_IP', 
       DEST_PORT as 'Destination_Port', 
       BYTES 
from TBL_PROBE_DAILY 
where DAYSTAMP >= '2010-03-04' and DAYSTAMP <= '2010-03-04' 
  and TIMESTAMP >= FROM_UNIXTIME(1267653600) and TIMESTAMP <= FROM_UNIXTIME(1267687228) 
order by bytes desc limit 20;

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

Ключом к объяснению является длина ключа: он показывает, какая часть значения индекса фактически используется. Вероятно, это то же значение (3), даже если вы заставляете его использовать нужный вам индекс.

...