Какие индексы можно использовать для улучшения этого запроса? - PullRequest
0 голосов
/ 11 сентября 2009

Этот запрос выбирает все уникальные сеансы посетителей в определенном диапазоне дат:

select distinct(accessid) from accesslog where date > '2009-09-01'

У меня есть индексы в следующих полях:

  • accessid
  • дата
  • некоторые другие поля

Вот как выглядит объяснение:

mysql> explain select distinct(accessid) from accesslog where date > '2009-09-01';
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
| id | select_type | table     | type  | possible_keys        | key  | key_len | ref  | rows  | Extra                        |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
|  1 | SIMPLE      | accesslog | range | date,dateurl,dateaff | date | 3       | NULL | 64623 | Using where; Using temporary |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+


mysql> explain select distinct(accessid) from accesslog;
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table     | type  | possible_keys | key      | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
|  1 | SIMPLE      | accesslog | index | NULL          | accessid | 257     | NULL | 1460253 | Using index |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+

Почему запрос с предложением даты не использует индекс доступа?

Существуют ли какие-либо другие индексы, которые я могу использовать для ускорения запросов для отдельных идентификаторов доступа в определенные интервалы дат?

Редактировать - Разрешение

Уменьшение ширины столбца на accessid с varchar 255 до char 32 позволило сократить время запроса на ~ 75%.

Добавление индекса date+accessid не влияло на время запроса.

Ответы [ 6 ]

5 голосов
/ 11 сентября 2009

Индекс на (date,accessid) может помочь. Однако перед настройкой индексов я бы порекомендовал проверить тип вашего столбца accessid. EXPLAIN говорит, что длина ключа составляет 257 байт, что очень похоже на столбец идентификатора. Вы используете VARCHAR(256) для accessid? Если это так, не можете ли вы использовать более компактный тип? Если это число, оно должно быть на INT (SMALLINT, BIGINT, в зависимости от ваших потребностей), и если это буквенно-цифровой идентификатор, может ли действительно быть длиной 256 символов? Если его длина фиксирована, вы не можете вместо этого использовать CHAR (CHAR(32))?

2 голосов
/ 11 сентября 2009

Ваша проблема в том, что ваше условие является предложением диапазона (в столбце даты).

Многостолбцовый индекс date-> accessid, скорее всего, не поможет ситуации, так как MySQL не может использовать столбцы индекса после условия диапазона. Теоретически они должны иметь возможность использовать его для покрытия вычислений в этом случае, но, похоже, это недостаток в MySQL, я никогда не получал его, чтобы успешно использовать многостолбцовый индекс в этой ситуации.

Вы можете попытаться создать индекс (date, accessid), надеясь, что он будет использовать его для покрытия запроса (поэтому вам не нужно будет нажимать на какие-либо таблицы), но я не очень надеюсь. Там не так много, вы можете сделать.

Edit:

Мой ответ любезно предоставлен Высокопроизводительный MySQL - второе издание , на вес золота, если вам предстоит серьезная разработка MySQL.

0 голосов
/ 11 сентября 2009

Почему в запросе с предложением даты не используется индекс доступа?

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

Если бы он использовал индекс доступа, он также должен прочитать каждую строку (а также каждую запись индекса), чтобы увидеть, соответствует ли дата критерию поиска. Это означает чтение всего индекса и всей таблицы - фактически, в контексте было бы лучше игнорировать индекс, но я начал с «если бы он использовал индекс доступа».

Существуют ли какие-либо другие индексы, которые я могу использовать для ускорения запросов для отдельных идентификаторов доступа в определенные промежутки времени?

В зависимости от сложности оптимизатора, индекс на (date, accessid) может улучшить ситуацию. Он может выполнять поиск по диапазону в ведущем столбце индекса, а конечный столбец означает, что ему не нужно обращаться к данным в таблице, чтобы установить accessid - информация находится в индексе. Таким образом, это может преобразовать запрос, который обращается к индексу и таблице, в тот, который обращается только к индексу, - что уменьшит количество необходимых операций ввода-вывода и, следовательно, повысит производительность запроса.

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

0 голосов
/ 11 сентября 2009

У меня нет возможности проверить это, но я бы определенно попытался добавить индекс , охватывающий и accessid, и дату .

Оптимизация индекса, если часто она похожа на алхимию. Разные СУБД ведут себя по-разному, и иногда вам нужно просто попробовать (и потерпеть неудачу) различные комбинации. Я не говорю, что невозможно рассуждать. Это во многих случаях, но до определенного момента. Часто просто быстрее и легче следовать своему инстинкту.

0 голосов
/ 11 сентября 2009

Запрос использует индекс 'date', потому что это то, что вы используете в предложении where.

Это единственный разумный вариант, если он использовал индекс идентификатора доступа, ему нужно было бы прочитать все строки accessid, затем проверить дату до нее и только потом решить, была ли она отличной.

Если это действительно большая таблица, может помочь составной индекс по дате и accessid.

0 голосов
/ 11 сентября 2009

Почему в запросе с предложением даты не используется индекс доступа?

Потому что использование индекса даты более эффективно. Это потому, что он может сократить пространство поиска быстрее.

По крайней мере одна СУБД (DB2 / z, я мало знаю о MySQL) выиграла бы от индекса по дате + accessid, поскольку идентификаторы доступа будут отсортированы в пределах дат в этом индексе. Эта СУБД будет использовать ключ date + accessid для эффективного использования предложения where для сокращения пространства поиска и для возврата различных значений accessid в этом пространстве.

Является ли MySQL таким умным, я понятия не имею. Мое предложение было бы попробовать и посмотреть (это лучший ответ на большинство вопросов оптимизации БД).

...