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

标签 mysql innodb indexing

我最近读到关于 innodb 表,在 (something,primary_key) 上放置索引是多余的,因为主键自动与所有二级索引聚集在一起。 因此,为了减小索引大小,我复制了我的表,删除了冗余主键,并进行了一些测试查询,我发现它的行为与具有“冗余”主键的原始表不同。

Explain 告诉我它正在做相交:

Using intersect(idx_faver_idx_id,PRIMARY); 

下面是查询。如果我删除 "AND Favorite.id < 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

最佳答案

InnoDB 二级索引节点包含主键值,但如果要对 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:在描述复合索引时请不要使用术语“聚集”,因为聚集与索引的含义不同。聚簇索引改变表数据的存储以匹配索引的顺序。 InnoDB 主键始终是聚集索引,因为数据行存储在主键索引的叶节点中。


关于您的评论:请记住,针对主索引的“范围”查询可能优于针对二级索引的“ref”查询。

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

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

我说“可能是”不是为了使用狡猾的话,而是因为更好的选择实际上取决于有多少行与任一条件匹配。通常优化器非常擅长进行这种评估,因此没有必要使用 FORCE INDEX 来覆盖其行为。

关于mysql - innodb 聚集二级索引和范围查询的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8190467/

相关文章:

python - 根据 Pandas 数据框中的列标签对数据进行分组

ios - __NSArrayM 索引越界

mysql - 有没有办法在 MySQL 中结合 IN 和 LIKE?

php - 将多个文本文件上传到 MySQL

mysql - 加快在 MySQL 中的插入

MySQL "remembers"删除InnoDB表

Postgresql:查询 jsonb 列 - 索引并不能使其更快

php - 在 MySQL 表中存储盐是否安全?

php - 将多项选择下拉列表保存到 1 列中

php - Mysql/InnoDB 停止在 Linode 服务器上工作