Mysql覆盖vs复合vs列索引

Son*_*ngo 36 mysql sql indexing composite-index covering-index

在以下查询中

SELECT  col1,col2
FROM    table1
WHERE   col3='value1'
  AND   col4='value2'
Run Code Online (Sandbox Code Playgroud)

如果我在col3上有一个单独的索引,而在col4上有另一个索引,那么在这个查询中将使用哪一个?

我在某处读到,对于查询中的每个表,只使用一个索引.这是否意味着查询无法使用这两个索引?

其次,如果我同时使用col3col4创建了一个复合索引,但在WHERE子句中只使用了col3,那么性能会更差吗?例:

SELECT  col1,col2
FROM    table1
WHERE   col3='value1'
Run Code Online (Sandbox Code Playgroud)

最后,在所有情况下使用覆盖索引是否更好?MYISAM和innodb存储引擎有什么不同?

Joh*_*ica 43

覆盖索引与复合索引不同.

如果我在col3上有一个单独的索引,而在col4上有另一个索引,那么在这个查询中将使用哪一个?

具有最高基数的索引.
MySQL会统计哪些索引具有哪些属性.
将使用具有最大辨别力的索引(在MySQL的统计中显而易见).

我在某处读到,对于查询中的每个表,只使用一个索引.这是否意味着查询无法使用这两个索引?

您可以使用子选择.
或者甚至更好地使用包含col3和col4的复合索引.

其次,如果我同时使用col3和col4创建了一个复合索引,但在WHERE子句中只使用了col3,那么性能会更差吗?例:

复合索引
正确的术语是compound索引,而不是复合.
仅使用复合索引的最左侧部分.
因此,如果索引定义为

index myindex (col3, col4)  <<-- will work with your example.
index myindex (col4, col3)  <<-- will not work. 
Run Code Online (Sandbox Code Playgroud)

请参阅:http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

请注意,如果选择最左侧的字段,则可以在where子句中不使用索引的该部分.
想象一下,我们有一个复合指数

Myindex(col1,col2)

SELECT col1 FROM table1 WHERE col2 = 200  <<-- will use index
SELECT * FROM table1 where col2 = 200     <<-- will NOT use index.  
Run Code Online (Sandbox Code Playgroud)

这样做的原因是第一个查询使用覆盖索引并对其进行扫描.
第二个查询需要访问该表,因此扫描索引没有意义.
这仅适用于InnoDB.

什么是覆盖索引
覆盖索引是指在查询中选择的所有字段都是covered索引的情况,在这种情况下,InnoDB(不是MyISAM)永远不会读取表中的数据,而只会使用索引中的数据加快选择速度.
请注意,在InnoDB中,主键包含在所有二级索引中,因此所有二级索引都是复合索引.
这意味着如果您在InnoDB上运行以下查询:

SELECT indexed_field FROM table1 WHERE pk = something
Run Code Online (Sandbox Code Playgroud)

MySQL将始终使用覆盖索引,不会访问实际的表.

  • 很棒的信息!!您是否有关于“索引myindex(col4,col3)&lt;&lt;-无法使用”的文档?我不信任您,但我只想阅读更多有关此的内容。 (2认同)
  • SELECT col1 FROM table1 WHERE col2 = 200 << - 将使用index(col1,col2).是的,但是......它必须扫描整个索引.这可能比扫描表更好_但只是因为索引可能比表小. (2认同)

Sam*_*m T 5

我赞成Johan对完整性的回答,但我认为他对二级索引的陈述不正确和/或令人困惑;

Note that in InnoDB the primary key is included in all secondary indexes, 
so in a way all secondary indexes are compound indexes.

This means that if you run the following query on InnoDB:

SELECT indexed_field FROM table1 WHERE pk = something

MySQL will always use a covering index and will not access the actual table.
Run Code Online (Sandbox Code Playgroud)

虽然我同意二级索引中的主键是INCLUDED,但我不同意MySQL"将始终在此处指定的SELECT查询中使用覆盖索引".

要了解原因,请注意在这种情况下始终需要完整的索引"扫描" .这与"搜索"操作不同,而是二次索引内容的100%扫描.这是因为主键不对二级索引进行排序 ; 它按"indexed_field"排序(否则它不会用作索引!).

鉴于后一事实,将存在这样的情况:"寻找"主键,然后从"实际表"中提取indexed_field,而不是从二级索引提取效率更高.