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

0

У меня есть 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 ;

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

Теги:
indexing
myisam
innodb

1 ответ

0
Лучший ответ

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

КЛЮЧ 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 script. У вас есть доступ к phpMyAdmin? Затем попробуйте запустить этот запрос, добавленный EXPLAIN. Это даст вам несколько советов.

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

/Карстен

  • 0
    Интересно, что я не знал, что OR эффективно удаляет использование индексов. Проблема в том, что мне нужно получить рабочий заказ, который либо заканчивается, либо начинается, либо полностью содержится в выбранном диапазоне дат. Я бы подумал, что в двухстороннем порядке, три отдельных поиска и фильтрация дубликатов по факту будут медленнее, не так ли? Этот запрос является примером, поскольку иногда существуют и другие фильтры, но теоретически этот запрос можно вызывать часто.
  • 0
    Относительно скорости: это зависит исключительно от количества записей в вашей таблице. Ваш запрос выполняет "сканирование таблицы", т.е. просматривает все записи в таблице. Если в таблице всего несколько тысяч записей, это не должно сказываться на производительности. Если у вас есть, скажем, 50.000 записей или более, вы можете начать видеть проблемы с производительностью.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню