索引(在MYSQL中也叫做“键(key)”)是存储引擎中用户快速找到记录的一种数据结构,这是索引的基本功能(可以对比书本的目录,就是索引),索引应该是对查询性能优化最有效的手段。
在MYSQL中,存储引擎先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行
例如: selectfirst_name from sakila.actor where actor_id = 5;
如果在actor_id上建立索引,则MYSQL将使用索引找到actor_id=5的行,然后返回所有包含该值的数据行。
MYSQL的索引类型有B-Tree索引、哈希索引、空间数据索引(R-Tree)、全文索引
没有特别的指明类型,多半是B-Tree索引,它使用B-Tree数据结构来存储数据。B-Tree的知识概念可以参考(https://baike.baidu.com/item/B-tree/6606402?fr=aladdin),在这里不做具体展开,因为更详细的我也不是很懂。
MySIAM使用前缀压缩技术使得索引更小,InnoDB则按照原数据格式进行存储,再如MyISAM 索引通过数据的物理位置引用被索引的行,而InnoDB则根据主键引用被索引的行。
B-Tree通常意味着所有的值都是按顺序排列存储的,并且每一个叶子页到根的距离相同。B-Tree所有能够加快访问数据的速度,因为存储引擎不再需要进行全表搜索来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点的槽中存放了指向子节点的指针,存储引擎根据指针向下查找。通过比较节点页的值和要查找的值就可以找到合适的指针进入下层节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么找到对应的值,要么该记录就不存在。
B-Tree对索引列是顺序组织存储的,所以很适合查找范围数据。例如在一个基于文本域的索引树上,按字母传递连续的值进行查找是非常合适的。例如要查找A-K开头的名字,这样效率会很高。
索引对多个值进行排序的依据是CREATE_TABLE语句中定义索引时序的顺序,如果你定义的是first、last、time、三个字段顺序索引,那么索引将会按照顺序来进行排序。
B-Tree索引适用于全键值、键值范围、键前缀查找(这个只适用于根据最左前缀的查找),对下列的查询类型有效:
全值匹配(和索引中的所有列匹配)
匹配最左前缀(只使用索引的第一列)
匹配列前缀(匹配某一列的开头部分,例如首字母为J)
匹配范围值(例如查询A~J范围的,只使用索引的第一列)
精确匹配某一列并范围匹配另外一列(例如查找姓为Jack名字开头为T的数据)
只访问索引的查询(查询只需要范围)
如果不是按照索引的最左列开始查找,则无法使用索引
不能跳过索引中的列,如果索引建立的顺序是(first,second,last),无法索引到条件为first、last,只能匹配到first(因为跳过了second)
如果查询中有某个列的范围查询,则右边所有的列都无法使用索引优化(first=1 and second like ‘J%’)and last =1 ,只能索引到first、second、last无法索引到
结论:索引的列顺序非常重要!!!查询条件的顺序非常重要!
哈希索引(hash index)基于哈希表实现,只有精确匹配索引的所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希是一个较小的值,并且对不同键值的行计算出来的哈希码也不一样。哈希码是一个较小的值,对不同键值的行计算出来的哈希码也不一样。哈希码将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据航的指针。
注意:只有memory引擎显性支持哈希索引,menory同时支持B-Tree索引,memory是支持非唯一哈希索引的,如果多个列的哈希值相同,name索引会以链表的方式记录存放多个指针到同一个哈希条目中。
例子:select * from table where fname=’first’;
查询过程:计算first的哈希值、假设为2323,使用该值寻找对应的记录指针,在索引中找到2323对应的第45行指针,再比较第三行的值是否为‘first’,确保找到该行。
哈希索引只包含哈希值和指针,不存储字段值,根据指针访问内存中的行的值
哈希索引数据并不是按照索引值顺序存储,无法用于排序
哈希索引不支持部分索引列匹配查找,因为哈希索引始终是使用索引列中的全部内容来计算哈希值。索引(A,B)建立哈希索引,如果查询只有数据列A,则无法使用该索引
哈希索引只支持等值的比较查询,不支持任何的范围查询
访问哈希的数据非常快,除非哈希冲突(不同的索引值却有相同的哈希值)
如果哈希冲突的话,一些索引维护操作的代价也很高。例如在选择性很低的列(哈希冲突很多)上建立哈希索引,当从列中删除一行时,存储引擎需要遍历对应的哈希值的链表中的每一行,找到并删除对应行的引用,冲突越多代价越大。
创建自定义哈希索引
例如 select idfrom table1 where url=https://www.csdn.net;我们可以这么优化:
1、删除原来Url列上的索引,新增一个被索引的url_crc列,使用CRC32做哈希,就可以使用下面的查询方式:select id from table1 where url=“https://www.csdn.net”and url_crc=CRC32(“https://www.csdn.net/”);
2、创建触发器,当插入url时候,会在url_crc字段上生成一个哈希码!
Create trigger table1hash_crc_insbefore insert on table1 for each row begin set new.url_crc=crc32(new.url);
Create trigger table1hash_crc_updatebefore update on table1 for each row begin set new.url_crc=crc32(new.url);
处理哈希冲突需要在使用哈希索引进行查询时候,在where中包含常量,例如上面where url=https://www.csdn.net and url_crc= CRC32(“https://www.csdn.net”);
空间数据索引(R-Tree)、全文索引(特殊类型的索引,他查找的是文本中的关键词,而不是直接比较索引中的词,全文索引更像是搜索引擎做的事,全文索引适用于MATCH AGAINST 操作)
1、 索引大大减少了服务器需要扫描的数据量
2、 索引可以帮助服务器避免排序和临时表
3、 索引可以将随机I/O变为顺序I/O
三星系统:索引将相关的记录放到一起则为一星;索引中的数据顺序和查找中的排列顺序一致则二星、索引中的列包含了查询中需要的全部列则三星;