Индекс не используется там, где он может и должен - PullRequest
2 голосов
/ 01 сентября 2011

У меня есть (большая) таблица, по которой я делаю запрос, используя 3 поля в WHERE.У одного из этих полей есть индекс (дата), и я ищу хиты за последние 3 месяца.Хотя этот запрос никогда не будет быстрым, по крайней мере, я надеюсь, что будет использоваться индекс на эту дату.

Это мой запрос:

SELECT id
FROM statsTable
WHERE 1
   AND ip            =  'ipgoeshere'
   AND anotherstring =  'Quite a long string goes here, something like this or even longer'
   AND `date`        >  DATE_ADD( NOW( ) , INTERVAL -3 MONTH ) 

И это объясняет:

id  select_type table       type    possible_keys   key     key_len ref     rows    Extra
1   SIMPLE      statsTable  ALL     date            NULL    NULL    NULL    4833721 Using where; Using filesort   

Это полное сканирование таблицы, число строк отключено из-за подсчета строк INNODB, я думаю, но это все из них. Это занимает около 30 секунд.

Если я форсирую индекс таким образом, я получаю ожидаемый результат:

SELECT id
FROM statsTable FORCE INDEX (date)
WHERE 1
   AND ip            =  'ipgoeshere'
   AND anotherstring =  'Quite a long string goes here, something like this or even longer'
   AND `date`        >  DATE_ADD( NOW( ) , INTERVAL -3 MONTH ) 

Опять объяснение:

id  select_type table       type    possible_keys   key     key_len ref     rows    Extra
1   SIMPLE      statsTable  range   date            date    8       NULL    1120172 Using where

Теперь у нас «только» миллион результатов, но это делается «быстро» (например, 3 секунды вместо 30).

Таблица:

CREATE TABLE IF NOT EXISTS `statsTable` (

  `id`            int(11) unsigned NOT NULL AUTO_INCREMENT,
  `date`          datetime NOT NULL,
  `ip`            varchar(15) NOT NULL,
  `anotherstring` varchar(255) NOT NULL,

  PRIMARY KEY (`id`),
  KEY `date` (`date`)

) ENGINE=InnoDB;

Странная вещь: у меня эта таблица работает и в другой базе данных (работает на другом сервере), и в этом случае используется индекс IS.Я не вижу, в чем может быть проблема здесь.Есть ли настройка, которую я пропустил?Или это может быть какая-то другая незначительная разница?Помимо различий, я не понимаю, почему в приведенном выше запросе не использовался ключ.

Я запустил OPTIMIZE TABLE и, как предложил @DhruvPathak, ANALYZE TABLE, но объяснение остается прежним.Я также попытался ALTER TABLE, как предложил друг, перестроить индекс.Не повезло.

Ответы [ 3 ]

1 голос
/ 01 сентября 2011

в зависимости от формата вашего запроса, идеальный индекс должен быть на

ip, date

или

ip, date, anotherstring <-- this could be overkill

и

order by null <-- eliminate the file sort

наконец, это может быть вашдругая база данных содержит гораздо меньшую запись

1 голос
/ 01 сентября 2011

Индекс не используется, потому что планировщик выполнения решает, что лучше выполнить полное сканирование таблицы, чем использовать индекс.Это происходит, когда индекс недостаточно избирателен для запроса.

Если даты в проверке диапазона составляют более 10-20% всей таблицы, то планировщик решает, что сканирует (последовательно) всю таблицубудет быстрее, чем использование индекса и извлечение строк, попадающих в этот диапазон (это извлечение не будет последовательным, поскольку строки будут разбросаны по всей таблице).

Вот почему вы видите разное поведение с разными наборамиданных.


Чтобы ваш запрос работал лучше всего, вы можете создать индекс для:

(ip, yourDateField)

или

(anotherstring, yourDateField)

или

(ip, anotherstring, yourDateField)

Я думаю, что первый вариант будет достаточно избирательным.Нет необходимости добавлять длинное поле VARCHAR(255) в индекс.В качестве альтернативы используйте FORCE INDEX, который в вашем случае работает нормально.

1 голос
/ 01 сентября 2011

Запустите ANALYZE TABLE один раз и посмотрите, поможет ли это исправить выбор оптимизатора.

http://dev.mysql.com/doc/refman/5.0/en/analyze-table.html

Это также поможет: MySQL не использует индексы с предложением WHERE IN?

Можете ли вы попробовать отредактировать ваш запрос?

Почему в запросе присутствует избыточное условие ИСТИНА ГДЕ 1?

Изменить

SELECT id
FROM statsTable
WHERE 1
   AND ip            =  'ipgoeshere'
   AND anotherstring =  'Quite a long string goes here, something like this or even longer'
   AND `date`        >  DATE_ADD( NOW( ) , INTERVAL -3 MONTH ) 

К

SELECT id
FROM statsTable
where  `date`        >  DATE_ADD( NOW( ) , INTERVAL -3 MONTH ) 
AND ip            =  'ipgoeshere'
AND anotherstring =  'Quite a long string goes here, something like this or even longer'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...