我最近在使用innodb表时读到,将索引置于(某些东西,primary_key)是多余的,因为主键自动与所有二级索引聚类。 因此,为了减少索引大小,我复制了我的表,删除了冗余主键,并进行了一些测试查询,我发现它与原始表的行为与“冗余”主键的行为不同。
解释告诉我它正在做一个交叉:
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
答案 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来覆盖其行为。