Частичные индексы MySQL по полям varchar и группировка по оптимизации - PullRequest
2 голосов
/ 08 апреля 2011

У меня проблемы с групповым запросом в MySQL.

Вопрос

Есть ли причина, по которой в запросе не будет использоваться 10-символьный частичный индекс в поле varchar (255) для оптимизации группы с помощью?

Подробности

Моя настройка:

CREATE TABLE `sessions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `ref_source` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `guid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `initial_path` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `referrer_host` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `campaign` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_sessions_on_user_id` (`user_id`),
  KEY `index_sessions_on_referrer_host` (`referrer_host`(10)),
  KEY `index_sessions_on_initial_path` (`initial_path`(10)),
  KEY `index_sessions_on_campaign` (`campaign`(10))
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Некоторые столбцы и индексы здесь не отображаются, поскольку они не влияют на проблему.

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

SELECT COUNT(*) AS count_all, referrer_host AS referrer_host FROM `sessions` GROUP BY referrer_host;

Объяснение дает:

+----+-------------+----------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+----+-------------+----------+------+---------------+------+---------+------+--------+---------------------------------+
|  1 | SIMPLE      | sessions | ALL  | NULL          | NULL | NULL    | NULL | 303049 | Using temporary; Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+--------+---------------------------------+

У меня есть частичный индекс на referrer_host, но он не используется.Даже если я попытаюсь USE INDEX или FORCE INDEX, это не поможет.Объяснение такое же, как и производительность.

Если я добавлю полный индекс на referrer_host вместо 10-символьного частичного индекса, все будет работать лучше, если не мгновенно.(350 мс против 10 секунд)

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

Ответы [ 3 ]

1 голос
/ 08 апреля 2011

Вы группируете по referrer_host для всех строк в таблице. Поскольку в ваш индекс не входит referrer_host (он содержит первые 10 символов!), Он будет сканировать всю таблицу.

Держу пари, что это быстрее, хотя и менее подробно:

SELECT COUNT(*) AS count_all, substring(referrer_host,1,10) AS referrer_host FROM `sessions` GROUP BY referrer_host;

Если вам нужен полный реферер, индексируйте его.

1 голос
/ 05 ноября 2011

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

с частичным индексом, движок не знает значение referrer_host, пока не просмотрит запись.Он должен сканировать всю таблицу!

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

1 голос
/ 08 апреля 2011

Попробуйте этот запрос:

EXPLAIN SELECT COUNT(referrer_host) AS count_all, referrer_host  FROM `sessions` GROUP BY referrer_host;

Теперь счетчик для группы будет сброшен по referrer_host = null, но я не уверен, есть ли другой способ обойти это.

...