innodb聚集二级索引和范围查询的问题

时间:2011-11-18 23:36:44

标签: mysql innodb indexing

我最近在使用innodb表时读到,将索引置于(某些东西,primary_key)是多余的,因为主键自动与所有二级索引聚类。 因此,为了减少索引大小,我复制了我的表,删除了冗余主键,并进行了一些测试查询,我发现它与原始表的行为与“冗余”主键的行为不同。

解释告诉我它正在做一个交叉:

Using intersect(idx_faver_idx_id,PRIMARY); 

以下是查询。如果我删除了“AND Favoriteid< 25103182”,那么它会按预期工作并使用正确的索引(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 个答案:

答案 0 :(得分:1)

InnoDB二级索引 leaf 节点包含主键值,但如果要对ID值进行范围查询,则需要非叶索引的节点包括主键值。

如果您只在选择列表中选择ID,那么将主键添加到索引定义是多余的。例如:

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

任一索引都会使以下查询成为仅索引查询。 InnoDB更喜欢更紧凑的索引s。它仍然可以是仅索引查询,因为索引的叶节点提供ID值。

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

但是当你在ID上也有不等式或范围条件时,它也会从包含非叶子节点中的ID值的索引中获得更多好处。它可以利用ID值在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:请不要在描述复合索引时使用术语“clustered”,因为clustered意味着索引有所不同。聚簇索引会更改表数据的存储以匹配索引的顺序。 InnoDB主键始终是聚簇索引,因为数据行存储在主键索引的叶节点中。


重新评论:请记住,针对主索引的“范围”查询可能优于针对辅助索引的“ref”查询。

当您的查询使用辅助索引时,它基本上必须每行进行两次树遍历:首先搜索辅助索引以获取它找到主键值的叶节点,然后第二个使用该主键值来搜索主(聚集)索引以获取其余列。

对于查询来说,针对主索引执行范围查询总体上可能更便宜,因此它会找到足够小的行子集,然后将其他条件应用于它找到的列。它没有使用二级索引,但它仍然是一个胜利,因为它只需要每行进行一次树遍历。

我说“可能”不使用狡猾的词,但是因为更好的选择实际上取决于两种条件匹配的行数。通常,优化器非常擅长进行此评估,因此不必使用FORCE INDEX来覆盖其行为。