С этим типичным запросом, правильны ли эти индексы в моей таблице InnoDB, или я должен изменить их? - PullRequest
0 голосов
/ 05 октября 2010

У меня есть php-запрос, который выполняется довольно часто, как этот:

$query = 'SELECT * FROM work_orders '
    .'WHERE '    
        . "((end_time >= ?"
  . "AND start_time <= ?) "
        . "OR (start_time <= ? "
  . "AND end_time >= ? ) "
        . "OR (start_time >= ? "
  . "AND end_time <= ? )) ";

И таблица определяется как:

CREATE TABLE IF NOT EXISTS `work_orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `work_order_number` varchar(32) COLLATE latin1_general_ci NOT NULL,
  `start_time` datetime NOT NULL,
  `end_time` datetime NOT NULL,
  `client_name` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `location` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `note` varchar(255) COLLATE latin1_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `note_idx` (`note`),
  KEY `client_idx` (`client_name`),
  KEY `location_idx` (`location`),
  KEY `start_time_idx` (`start_time`),
  KEY `end_time_idx` (`end_time`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1 ;

Меня часто смущает, как мне создавать индексы. Это таблица с интенсивным чтением с большим поиском в данных, поэтому я индексирую каждый столбец, но наиболее часто выполняемый запрос использует 3 комбинации даты начала и окончания, чтобы определить, попадает ли рабочее задание в конкретный календарный ряд. Должен ли я иметь индексы start_time и end_time по отдельности, как я делаю в настоящее время, или я должен создать составной ключ из двух? Есть ли лучший способ настроить индексы в целом? Должен ли я даже использовать InnoDB? Я вообще не использую транзакции.

1 Ответ

0 голосов
/ 06 октября 2010

Этот ответ двоякий.Прежде всего, я бы сделал индекс как:

KEY start_time_idx (start_time, end_time)

НО (и это вторая проблема): ваш запрос не будетбыть в состоянии использовать любой из индексов.И вот почему:

SELECT *
FROM work_orders
WHERE (
  (end_time >= <some-date> AND start_time <= <some-date>)
  OR
  (end_time >= <some-date> AND start_time <= <some-date>)
  OR
  (end_time >= <some-date> AND start_time <= <some-date>)
)

Как только вы используете оператор OR, вы фактически отключаете использование индексов для полей, участвующих в операторе OR.Поскольку в вашем операторе WHERE нет других полей, которые не включены в оператор OR, индекс не будет использоваться.

Я уверен, что это выполняется в сценарии PHP.У вас есть доступ к phpMyAdmin?Затем попробуйте выполнить этот запрос с добавлением EXPLAIN.Это даст вам несколько советов.

Если таблица содержит много данных, вы можете изменить этот запрос на 3 запроса, каждый из которых запрашивает только один диапазон дат, а затем объединить результат в PHP.потом.

/ Карстен

...