应用场景
非常小的表:不建议使用索引,简单的全表扫描更高效
中到大型表:使用索引
特大型表:定位单条记录速度很慢且开销很大,建议使用分区、分表代替
类型
一、B-Tree 索引(按照顺序存储索引列,适合查找范围数据)
1. 对以下查询有效 (索引列(firstname,lastname,age))
加索引的列全部匹配 (例: 匹配firstname,lastname,age)
只匹配索引的第一列或前几列 (例:匹配firstname,lastname)
只匹配索引某一列的前一部分(例:匹配firstname的前两个字母)
匹配某一列并范围匹配另外一列 (例:匹配 firstname为Allen,lastname以字母K开头)
查询中的 ORDER BY、GROUP BY 操作,也能够打到 B-Tree索引
2. 对以下查询无效 (索引列(firstname,lastname,age))
不是按照索引最左边开始查询 (例:匹配lastname为Iverson,firstname为Allen 或者 单独查找 age)
不能跳过索引中的列 (例:匹配firstname,age)
查询中有某个列的范围查询,则其右边所有列都无法使用索引优化 (例:firstname='Allen' AND lastname LIKE 'I%' AND age = 26)
二、哈希索引(只有Memory引擎支持,索引列:firstname,lastname,age)
索引速度非常快
哈希索引用户无法order by 排序
哈希索引不支持部分索引列 (例:firstname='Allen' )
哈希索引只支持等值比较查询(例:=、in( )、<=>),不支持范围查询(例:age>19)
哈希索引不适用于值比较单一的列(例:性别列)
哈希索引存储的是列的哈希值
当需索引的列值很长时(例:url列),建议使用HASH索引,如果使用的B-Tree索引,存储的内容就会很大,而HASH索引是存储哈希值
哈希冲突:不同的索引列值,却有相同的哈希值
三、空间数据索引(MyISAM表支持空间索引)
用作地理数据存储,此类索引无须前缀查询
四、全文索引(只能在MyISAM表中创建)
全文索引查找的是文本中的关键词,而不是直接比较索引中的值,此类索引更类似于搜索引擎做的事情,而不是简单的WHERE条件匹配,全文索引适用于MATCH AGAINST操作
索引策略
一、有时候需要索引很长的字符列,这会让索引变得大且慢。可以使用模拟哈希索引和使用前缀索引两种策略
1、模拟哈希索引
思路:还是使用B-Tree进行查找,但是使用哈希值而不是键本身进行索引查找。需要做的就是在查询的WHERE子句中手动指定使用哈希函数,伪哈希索引的缺陷是需要在插入和更新时,维护哈希列的哈希值。(不建议使用SHA1()和MD5()作为哈希函数,因为这两个函数计算出来的哈希值非常长)
例: 普通B-Tree索引
SELECT id FROM url WHERE url ='http://www.baidu.com';
B-Tree + HASH 索引(模拟哈希索引)
① 删除原来url列上的索引;
② 新增一个被 B-Tree 索引的列 url_crc ,使用 CRC32将url转化成哈希值;
③ 查询方式:
SELECT id FROM url WHERE url_crc=CRC32('http://www.baidu.com') AND url ='http://www.baidu.com';(注:一定需要匹配 url ='http://www.baidu.com',因为可能出现哈希冲突,不同的索引列值有相同的哈希值,具体见《高性能MySQL》150)
④ 利用触发器,在 insert 和 update 操作时,将url转化成哈希值
2、使用前缀索引(B-Tree索引)
基数:不重复的索引值
索引的选择性:不重复的索引值和数据表的记录总数的比值
索引的选择性越高,查询效率越高。为了提高查询效率,需要选择合适的前缀长度,以保证较高的选择性,同时又不能太长(以便节约空间)。
例( 见《高性能MySQL》城市例子 154 155 156,为城市表的city字段建立索引):
一、查找出现频次前10的城市
二、查找3个前缀字母出现频次
通过对比数据可知,每个前缀都比原来城市出现的次数更多,因此唯一前缀比唯一城市要少得多。我们需要增加前缀长度,直到前缀出现的次数接近完整列出现的次数。当前缀长度增加为7时,前缀出现的次数接近于完整列出现的次数,所以设置前缀长度为7,索引效率是最高的。 那我们是怎么知道前缀长度为7位时,索引效率最高呢,当然不可能一个一个地去试,要想得到最合适、效率最高的前缀长度,只需要计算不同长度的选择性,最接近完整列选择性的长度,一般就是最合适的长度。如下:
一、获取完整列的选择性
二、获取不同前缀长度的选择性
前缀索引页有它的缺点,MySQL无法使用前缀索引做 ORDER BY和 GROUP BY,也无法使用前缀索引做覆盖扫描。
二、选择合适的索引列顺序(B-Tree索引)
需执行的语句:
SELECT * FROM payment WHERE staff_id =2AND customer_id =584;
需设置索引:staffid 、customerid
考虑: 多列索引(staffid 、customerid)的顺序
根据全局基数和选择性 (见《高性能MySQL》城市例子 159 160 161)决定多列索引的顺序
查找出两个字段的选择性和全局基数
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,(选择性)
COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,(选择性)
COUNT(*)FROM payment\G
哪个字段选择性更高,则将此字段作为索引的第一列 注:此方法也有它的缺陷,当某些条件值的基数比正常值高的时候,问题就来了。如在某些应用程序中,对于没有登录的用户,都将其用户名记录为 guset,guset就成为了一个特殊用户,一旦查询涉及这个用户,那么和其他正常用户的查询就不一样。