Проблема с кластерным вторичным индексом innodb и запросами диапазона - PullRequest
3 голосов
/ 19 ноября 2011

Недавно я прочитал, что в таблицах innodb указание индекса (что-то, primary_key) является избыточным, поскольку первичный ключ автоматически кластеризуется со всеми вторичными индексами.Поэтому, чтобы уменьшить размер индекса, я скопировал свою таблицу, удалил избыточный первичный ключ и выполнил несколько тестовых запросов, и обнаружил, что он ведет себя не так, как моя исходная таблица с «избыточным» первичным ключом.

Объясните мне, что это пересечение:

Using intersect(idx_faver_idx_id,PRIMARY); 

Ниже приведен запрос.Если я удаляю Favorite. id <25103182" </b>, тогда он работает как положено и использует правильный индекс (idx_faver_idx_id).

SELECT `Item`.`id`, `Item`.`cached_image`, `Item`.`submitter_id`, `Item`.`source_title`, `Item`.`source_url`, `Item`.`source_image`, `Item`.`nudity`, `Item`.`tags`, `Item`.`width`, `Item`.`height`, `Item`.`tumblr_id`, `Item`.`tumblr_reblog_key`, `Item`.`fave_count`, `Favorite`.`id`, `Favorite`.`created` 
FROM `favorites2` AS `Favorite` 
LEFT JOIN `items` AS `Item` 
ON (`Favorite`.`notice_id` = `Item`.`id`) 
WHERE `faver_profile_id` = 1
AND `Favorite`.`removed` = 0
AND `Item`.`removed` = '0'
AND `Favorite`.`id` < 25103182
ORDER BY `Favorite`.`id` desc 
LIMIT 26

1 Ответ

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

Узел вторичного индекса InnoDB leaf включает значения первичного ключа, но если вы хотите выполнить запрос диапазона по значению идентификатора, ему нужны узлы non-leaf индекс для включения значений первичного ключа.

Если вы выбираете только идентификатор в вашем списке выбора, тогда избыточно добавлять первичный ключ в определение индекса. Например:

CREATE TABLE Favorite (
  id INT AUTO_INCREMENT PRIMARY KEY,
  something INT,
  KEY s (something),
  KEY s_with_id (something, ID)
);

Любой индекс сделает следующий запрос запросом только для индекса. InnoDB предпочитает более компактный индекс s. Это может быть запрос только для индекса, поскольку конечные узлы индекса предоставляют значение идентификатора.

mysql> EXPLAIN SELECT something, ID FROM Favorite WHERE something = 1\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: Favorite
         type: ref
possible_keys: s,s_with_id
          key: s
      key_len: 5
          ref: const
         rows: 48
        Extra: Using where; Using index

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

mysql> EXPLAIN SELECT something, ID FROM Favorite WHERE something = 1 and id < 10 \G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: Favorite
         type: ref
possible_keys: PRIMARY,s,s_with_id
          key: s_with_id
      key_len: 9
          ref: const
         rows: 1
        Extra: Using where; Using index

PS: Пожалуйста, не используйте термин «кластеризованный» при описании составного индекса, потому что кластеризованный означает что-то другое в отношении индексов. Кластерный индекс изменяет хранение табличных данных в соответствии с порядком индекса. Первичные ключи InnoDB всегда являются кластеризованным индексом, так как строка данных хранится в конечном узле индекса первичного ключа.


Ваш комментарий: имейте в виду, что запрос "диапазона" по первичному индексу может быть лучше запроса "ref" по вторичному индексу.

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

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

Я говорю «могло бы быть» не для того, чтобы использовать слова ласки, а потому, что лучший выбор действительно зависит от того, сколько строк соответствует одному из условий. Обычно оптимизатор хорошо справляется с этой оценкой, поэтому нет необходимости использовать FORCE INDEX для переопределения его поведения.

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