【问题标题】:Issue with innodb clustered secondary index and range queriesinnodb 聚集二级索引和范围查询的问题
【发布时间】:2011-11-18 23:36:44
【问题描述】:

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

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

Using intersect(idx_faver_idx_id,PRIMARY); 

下面是查询。如果我删除 "AND Favorite.id 那么它会按预期工作并使用正确的索引 (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

【问题讨论】:

    标签: mysql innodb indexing


    【解决方案1】:

    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-tree 中排序的事实。

    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 主键始终是聚集索引,因为数据行存储在主键索引的叶子节点中。


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

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

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

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

    【讨论】:

    • 我注意到,当我执行 FORCE INDEX (idx_faver_idx_id) 时,查询会正确使用索引并且执行起来似乎非常快(类型也是“ref”而不是“range”)。你显然知道你的东西,所以我不怀疑你,只是想看看这个观察对你是否有意义。感谢您阐明“集群”的含义。
    猜你喜欢
    • 2016-06-13
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2021-09-07
    • 2017-11-25
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    相关资源
    最近更新 更多