SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 27.01.2009 15:42:42

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

Добрый день. Есть
Date1 типа DATE
Date2 типа DATE
Делаю запрос

Код:

... WHERE CAST(NOW() AS DATE) BETWEEN Date1 AND Date2

EXPLAIN показывает полный перебор таблицы. Пытался делать индексы как отдельно по Date1 и Date2, так и составной индекс (Date1 + Date2) - индексы не используются. Причем, даже в possible_keys их нет.
Пока делаю

Код:

WHERE Date1 >= CAST( NOW( ) AS DATE ) 
AND Date2 <= CAST( NOW( ) AS DATE )

- так используется хотя бы один индекс и перебор уже не all, а range. Но чувствую, что я что-то не так делаю smile

Подскажите, пожалуйста, как правильно использовать индексы в данной ситуации?

Неактивен

 

#2 28.01.2009 12:50:36

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

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

Отредактированно Magz (28.01.2009 13:11:36)

Неактивен

 

#3 28.01.2009 13:49:31

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

1. Лучше использовать CURDATE() вместо каста.
2. Вы не сможете построить простого решения этой проблемы. Дело в том, что сравнение >=
автоматически подразумевает, что текущий индекс будет использоваться в виде range.
Соответственно, если этот range выбирает половину таблицы - по второй половине таблицы
будет производиться where с отсеиванием результатов. Как правило, в таких случаях придумывают
какие-то способы денормализации таблиц. Сходу, впрочем, придумать такой способ для всех случаев
не могу.

Неактивен

 

#4 28.01.2009 16:00:13

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

1. Спасибо, изменил.
2. А если вместо "<=" и ">=" использовать строгое "<" и ">"?

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

Спасибо за участие! Самое главное - это то, что Вы указали направление, куда "копать"!

Неактивен

 

#5 28.01.2009 21:05:43

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

Сделал

Код:

... WHERE Date1 < DATE_SUB(CURDATE(), INTERVAL +1 DAY) AND
Date2 > DATE_SUB(CURDATE(), INTERVAL -1 DAY)

Запрос стал использвать объединенный индекс (Date1, Date2). Однако, все равно в explain Using temporary; Using filesort. Можно ли как-то оценить, какой индекс использовать лучше - по одному полю или по двум? Или вообще в данном случае разницы не будет?

Отредактированно Magz (28.01.2009 21:10:16)

Неактивен

 

#6 28.01.2009 21:19:55

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

Ха! Я разобрался в своей ситуации smile Я использую ORDER BY RAND() - как только убрал случайную сортировку, сразу пропали Using temporary; Using filesort. Видимо, в данном случае дешевле сделать случайную выборку из PHP.

Неактивен

 

#7 29.01.2009 20:01:00

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

Не верится, что ключ используется целиком smile Покажете, что получилось?

Неактивен

 

#8 30.01.2009 18:23:28

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Как построить индекс при (NOW() BETWEEN Date1 and Date2)?

paulus написал:

Не верится, что ключ используется целиком smile Покажете, что получилось?

Нет, ключ целиком так и не используется. Просто, в реальной жизни была несколько другая задача. У меня запрос выбирает данные из трех таблиц:

Код:

mysql> EXPLAIN SELECT o.id, o.Caption, o.Body, o.URL, o.URLText, b.`URL_to` url_stat, b.`id_Banner` id_stat
    -> FROM `context_Objects` o
    -> JOIN context_Areas a ON a.id_ContextObject = o.id
    -> AND a.id_ContextArea =10
    -> JOIN realto_Banners b ON b.id_Banner = o.id_Banner
    -> WHERE o.StartDate < CURDATE( )
    -> AND o.FinishDate > CURDATE( )
    -> ORDER BY RAND( )
    -> LIMIT 0 , 4;
+----+-------------+-------+--------+------------------------------------+------------------+---------+------------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                      | key              | key_len | ref                    | rows | Extra                                        |
+----+-------------+-------+--------+------------------------------------+------------------+---------+------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | o     | range  | PRIMARY,id_Banner,context_TwoDates | context_TwoDates | 3       | NULL                   |   41 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | a     | ref    | ContextIndex                       | ContextIndex     | 8       | db_realto3.o.id,const  |    1 | Using index                                  |
|  1 | SIMPLE      | b     | eq_ref | PRIMARY                            | PRIMARY          | 4       | db_realto3.o.id_Banner |    1 |                                              |
+----+-------------+-------+--------+------------------------------------+------------------+---------+------------------------+------+----------------------------------------------+
3 rows in set (0.00 sec)

Увидав Using temporary; Using filesort я стал разбираться с индексами на данную таблицу, стал моделировать ситуации, когда идет выборка по датам. Не смог найти оптимального решения для индексирования и задал вопрос. Потом, я продолжил опыты и убрав ORDER BY RAND() я добился того, что Using temporary; Using filesort ушли в небытие:

Код:

mysql> EXPLAIN SELECT o.id, o.Caption, o.Body, o.URL, o.URLText, b.`URL_to` url_stat, b.`id_Banner` id_stat
    -> FROM `context_Objects` o
    -> JOIN context_Areas a ON a.id_ContextObject = o.id
    -> AND a.id_ContextArea =10
    -> JOIN realto_Banners b ON b.id_Banner = o.id_Banner
    -> WHERE o.StartDate < CURDATE( )
    -> AND o.FinishDate > CURDATE( )
    -> LIMIT 0 , 4;
+----+-------------+-------+--------+------------------------------------+--------------+---------+-------------------------------+------+--------------------------+
| id | select_type | table | type   | possible_keys                      | key          | key_len | ref                           | rows | Extra                    |
+----+-------------+-------+--------+------------------------------------+--------------+---------+-------------------------------+------+--------------------------+
|  1 | SIMPLE      | a     | index  | ContextIndex                       | ContextIndex | 8       | NULL                          |  106 | Using where; Using index |
|  1 | SIMPLE      | o     | eq_ref | PRIMARY,id_Banner,context_TwoDates | PRIMARY      | 4       | db_realto3.a.id_ContextObject |    1 | Using where              |
|  1 | SIMPLE      | b     | eq_ref | PRIMARY                            | PRIMARY      | 4       | db_realto3.o.id_Banner        |    1 |                          |
+----+-------------+-------+--------+------------------------------------+--------------+---------+-------------------------------+------+--------------------------+
3 rows in set (0.00 sec)

Собственно, свою проблему в данном случае я решил. Но проблема с индексацией дат и периодов осталась. Я еще создам отдельный пост - оптимизирую сейчас сервис "Расписание", там вообще аховая ситуация smile Но это чуть позже smile

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson