Как проиндексировать два столбца даты для этого вида запроса - PullRequest
7 голосов
/ 17 февраля 2012

У меня MySQL-таблица, подобная этой:

CREATE TABLE `dates` (
`id`  int UNSIGNED NULL AUTO_INCREMENT ,
`object_id`  int UNSIGNED NOT NULL ,
`date_from`  date NOT NULL ,
`date_to`  date NULL ,
`time_from`  time NULL ,
`time_to`  time NULL ,
PRIMARY KEY (`id`)
);

, которая запрашивается в основном следующим образом:

SELECT object_id FROM `dates`
WHERE NOW() BETWEEN date_from AND date_to

Как лучше индексировать таблицу?Должен ли я создать два индекса, один для date_from и один для date_to или лучше использовать комбинированный индекс для обоих столбцов?

Ответы [ 4 ]

6 голосов
/ 17 февраля 2012

Для запроса:

WHERE NOW() >= date_from 
  AND NOW() <= date_to

Составной индекс (date_from, date_to) бесполезен.

Создайте оба индекса: (date_from) и (date_to) и пусть оптимизатор SQL принимает решение каждый разкакой использовать.В зависимости от значений и селективности оптимизатор может выбрать тот или иной индекс.Или ни один из них.Нет простого способа создать индекс, который будет учитывать оба условия.


(Пространственный индекс можно использовать для оптимизации такого условия, если вы можете перевести даты в широту и долготу).

Обновление

Моя ошибка.Индекс на (date_from, date_to, object_id) может и действительно используется в некоторых ситуациях для этого запроса.Если селективность NOW() <= date_from достаточно высока, оптимизатор решит использовать этот индекс, чем выполнять полное сканирование таблицы или использовать другой индекс.Это связано с тем, что это закрывающий индекс, то есть для извлечения данных из таблицы не требуется, требуется только чтение из данных индекса.

Незначительное примечание (не связано с производительностью, только правильность запроса).Ваше состояние эквивалентно:

WHERE CURRENT_DATE() >= date_from 
  AND ( CURRENT_DATE() + INTERVAL 1 DAY <= date_to
       OR  ( CURRENT_DATE() = NOW() 
         AND CURRENT_DATE() = date_to
           )
      )

Вы уверены, что хотите этого или хотите это:

WHERE CURRENT_DATE() >= date_from 
  AND CURRENT_DATE() <= date_to

Функция NOW() возвращает DATETIME, тогда как CURRENT_DATE() возвращает DATE, без временной части.

3 голосов
/ 18 февраля 2012

Вы должны создать индекс, охватывающий date_from, date_to и object_id, как объяснено ypercube. Порядок полей в индексе зависит от того, будет ли у вас больше данных за прошлое или будущее. Как отметил Эрвин в ответ на комментарий Санджея, поле date_to будет более избирательным, если у вас больше дат в прошлом и наоборот.

CREATE INDEX ON (date_to, date_from, object_id);
1 голос
/ 17 февраля 2012

Сколько строк по отношению к размеру вашей таблицы возвращает ваш запрос? Если это больше 10 процентов, я бы не стал создавать индекс, в любом случае, в любом случае, вы достаточно близки к сканированию таблицы. Если это значительно ниже 10 процентов, то в этом случае будет использовать индекс, связывающий (date_from, date_to, object_id), так что результат запроса может быть построен полностью из информации в индексе, без необходимости базы данных отслеживать данные таблицы, чтобы получить значение для object_id.

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

0 голосов
/ 17 февраля 2012

Создайте индекс с (date_from, date_to), так как этот единственный индекс будет использоваться для критериев WHERE

Если вы создаете отдельные индексы, MySQL должен будет использовать один или другой вместо обоих

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