У меня есть 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? Я вообще не использую транзакции.
Этот ответ в два раза. Прежде всего, я бы сделал индекс как:
КЛЮЧ 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.
/Карстен