最左原则
B-Tree索引和Hash索引的对比
对于B-tree和hash数据结构的理解能够有助于预测不同存储引擎下使用不同索引的查询性能的差异,尤其是那些允许你选择B-tree或者hash索引的内存存储引擎。
B-tree索引的特点
B-tree索引可以用于使用=,>,>=,<,<=或者between运算符的列比较。如果like的参数是一个没有以通配符其实的常量字符串的话也可以使用这种索引。
有时,即使有索引可以使用,MySQL也不使用任何索引。发生这种情况的场景之一就是优化器估算出使用该索引将要求MySQL去访问这张表的绝大部分记录。这种情况下,一个表扫描可能更快,因为它要求更少量的查询。但是,如果这样的一个查询使用了limit来检索只是少量的记录时,MySQL还是会使用索引,因为它能够更快的找到这点记录并将其返回。
Hash索引的特点
Hash索引有着与刚才讨论特点的相比截然不同的特点:
Hash索引只能够用于使用=或者<>运算符的相等比较(但是速度更快)。Hash索引不能够用于诸如<等用于查找一个范围值得比较运算符。依赖于这种单值查找的系统被称为“键-值存储”;对于这种系统,尽可能的使用hash索引。
优化器不能够使用hash索引来加速order by操作。这种类型的索引不能够用于按照顺序查找下一个条目。
MySQL无法使用hash索引估计两个值之间有多少行(这种情况由范围优化器来决定使用哪个索引)。如果你将一张MyISAM或InnoDB表转换成一个hash索引的内存表时,一些查询可能受此影响。
查找某行记录必须进行全键匹配。而B-tree索引,任何改建的左前缀都可用以查找记录。
最左前缀原则
通过实例理解单列索引、多列索引一级最左前缀原则
实例:现在我们想查出满足以下条件的用户ID
select uid from people where lname='liu' and fname='zhiquan' and age='12'
因为我们不想扫描郑飚,故考虑用索引
单列索引:
alter table people add index lname(lname);
将列建索引,这样就把范围限制在lname='liu'的结果集1上,之后扫描结果集1,产生满足fname='zhiquan'的结果集2,在扫描结果集2,找到age=12的结果集3,即最终结果。
由于建立了lname列的索引,与执行表的完全扫描相比,效率提高了很多,但我们要求扫描的记录数量仍旧远远超过了实际所需要的。虽然我们可以删除lname列上的索引,再创建fname或者age列的索引,但是,不论在哪个列上创建索引搜索效率仍旧相似。
2.多列索引:
alter table people add index lname_fname_age(lname,fname,age);
为了提高索引效率,我们需要考虑运用多列,由于索引文件以B-tree格式保存,所以我们不用扫描记录,即可得到最终结果。
注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。
3最左前缀:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了lname单列索引,lname,fname组合索引以及lname,fname,age组合索引。
注:在创建多列索引时,要根据业务需求,where自居中使用最频繁的一列放在最左边。
拓展:在网上看到一个关于最左前缀原则提出这么一个列子。
多列字段做索引,state/city/zipcode,想要索引生效的话,只能使用如下的组合
state/city/zipcode
state/city/
state
其他方式(如city,city/zipcode),则索引不会生效
这种现象是怎么导致的?和索引的存储方式有关吗?
所谓最左前缀原则就是先要看第一列,在第一列满足的条件下再看左边第二列,以此类推。
索引是因为B+树结构所以查找块,如果单看第三列是非排序的。
多列索引是先按照第一列进行排序,然后在第一列排好序的基础上再对第二列,如果没有第一列的话,直接访问第二列,那第二列可能是无序的,直接访问后面的列就用不到索引了。
所以如果不是在前面列的基础上而是在看后面的某一列,索引时失效的