(为什么)MySQL在这种情况下不能使用索引?

Chr*_*ris 7 mysql database indexing

1 - PRIMARY用于二级索引,例如(PRIMARY,column1)上的二级索引

2 - 我知道只要一个部件用于范围扫描,mysql就无法继续使用索引的其余部分,但是:IN (...,...,...)不被认为是范围,是吗?是的,它是一个范围,但我读过mysqlperformanceblog.com,IN其行为与BETWEEN根据索引的使用不同.

谁能证实这两点?或者告诉我为什么这不可能?或者它是如何可能的?

更新:

链接:
http://www.mysqlperformanceblog.com/2006/08/10/using-union-to-implement-loose-index-scan-to-mysql/
http://www.mysqlperformanceblog.com/2006/08/ 14/MySQL的-跟帖上工会的查询优化查询,分析/发表评论页面-1 /#评论-952521

更新2:嵌套SELECT的示例:

SELECT * FROM user_d1 uo 
WHERE EXISTS (
    SELECT 1 FROM `user_d1` ui
    WHERE ui.birthdate BETWEEN '1990-05-04' AND '1991-05-04'
    AND ui.id=uo.id
)    
ORDER BY uo.timestamp_lastonline DESC
LIMIT 20
Run Code Online (Sandbox Code Playgroud)

所以,外SELECT使用timestamp_lastonline用于排序,内或者PK与所述外或连接birthdate用于过滤.

如果MySQL不能在范围扫描上使用索引并进行排序,那么还有哪些其他选项而不是此查询?

esw*_*ald 2

主键的列当然可以在辅助索引中使用,但这通常不值得。主键保证唯一性,因此在主键之后列出的任何列都不能用于范围查找。唯一有帮助的时候是查询可以单独使用索引时

至于嵌套选择,额外的复杂性不应打败最简单的查询:

SELECT * FROM user_d1 uo 
WHERE uo.birthdate BETWEEN '1990-05-04' AND '1991-05-04'
ORDER BY uo.timestamp_lastonline DESC
LIMIT 20
Run Code Online (Sandbox Code Playgroud)

MySQL 将在一个birthdate索引或一个timestamp_lastonline它认为最有可能扫描更少行的索引之间进行选择。无论哪种情况,该列都应该是索引中的第一个列。该birthdate索引还将带来排序惩罚,但如果大量最近用户的出生日期超出该范围,则可能是值得的。

如果您希望控制顺序或可能提高性能,(timestamp_lastonline, birthdate)(birthdate, timestamp_lastonline)索引可能会有所帮助。如果没有,并且您确实需要首先根据生日进行选择,那么您应该从内部查询中进行选择,而不是对其进行过滤:

SELECT * FROM (
    SELECT * FROM user_d1 ui
    WHERE ui.birthdate BETWEEN '1990-05-04' AND '1991-05-04'
) as uo
ORDER BY uo.timestamp_lastonline DESC
LIMIT 20
Run Code Online (Sandbox Code Playgroud)

timestamp_lastonline即使这样,如果 MySQL 的优化器找到索引但没有索引,它也可能会选择重写查询birthdate

是的,IN (..., ..., ...)行为与 不同BETWEEN。只有后者才能有效地对索引使用范围扫描;前者会单独查找每个项目。