你的查询项是*,你的索引项只有一个source in ('a', 'b'),如果表里面不仅仅只有source(以及主键)这么一(两)列的话,那么毫无疑问的结果将进行回表(回表的意思就是每当你索引检索到1个满足条件的就再到表里面去查找符合查询条件的,每一次回表都产生一次随机IO);

走索引:

假设满足你索引条件的行数为N(总行数为R,索引过滤性为X%,N=R*X% 。举例来说一个性别类的索引,他的过滤性就是50%,那么N≈0.5R,这是多么恐怖的事情~),1次随机IO的时间是T,那么理论上产生的随机IO耗时为(因为每一次通过索引的回表查询都会是一次随机IO)TR=(N+1)*T(第一次索引扫描也是随机IO,所以这里是N+1)

假设顺序IO的时间为t,那么产生的顺序IO耗时为TS=N*t

所以产生的总耗时为TR+TS=NT+Nt=N(T+t)(这里忽略提取时间和某些语句可能产生的排序时间)

走全表:

而走全表的话只有一次随机IO,花费时间为TR=1*T

顺序IO花费时间为TS=R*t(走索引为Nt)

总时间为TR+TS=1*T+Rt

援引数据库索引优化与设计这本书对T和t的估值,T=10ms,t=0.01ms,可以看到如果索引的过滤性很好(X%很小),会导致N远小于R,那么这种情况下N(T+t)<1*T+Rt,走索引划算

反过来,很大的N导致随机IO=NT会非常恐怖

结果就是走索引的TR大于走全表的TR,而TS会因为时间太小,在巨大的TR面前显得无足轻重,最终的比拼成为TR的比拼,优化器权衡的结果就是索引耗时大于全表,最后就走全表了

多说一句,为什么建有覆盖索引的语句跑的那么快(对单表而言,对连接效果就不一定了),就是因为避免了回表产生的随机IO=NT,全程只有一次索引产生的随机IO,其余全是顺序IO,时间当然就快啦