联合索引不满足最左匹配原则
因为MySQL中索引存储的是按照一定的顺序子节点上,所有的子节点用一个双链表连接,这就是为什么可以使用范围查询。当不满足最左匹配,比如模糊查询%李,索引是按照最左边的顺序左边相同的数据排在一起,往右边存储不一致时,才会往后存储索引值。
索引列添加运算
当索引参与列运算之后,比如where a + 1 = 3,此时就要找到索引等于2的数据,而此时MySQL是无法获取到索引的真正的值属性.意思是无法转成where a = 2结果,也就无法使用索引查询数据。
索引列添加函数
添加函数之后,数据和原始数据也不一样,也就无法找到原始的数据了。
使用 or
B+ 树索引都存在字节点上,先从根节点往下找到对应的节点最小值然后遍历链表,一直遍历到符合数据的最大值为止,但是如果使用or就无法满足范围查询。
使用 not in
not in也不是范围查询,不符合范围查询的定义,
建索引的几大原则
-
最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
-
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。
-
尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。
-
索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)。
-
尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。