索引在MYSQl中也叫键(key),是存储引擎用于快速找到记录的一种数据结构。
例如:SELECT name FROM STUDNET WHERE ID=5;
如果MYSQL在ID上建立索引,则MYSQL将使用该索引找到ID=5的行,,也就是说MYSQL先在索引上按值进行查找,然后返回所有包含该值的数据行。
索引可以包含一列也可以包含多列,如果索引包含多列,那么列的顺序十分重要,因为MYSQL只能高效的使用索引的最左前缀。
索引有多种类型,可以在不同的场景提供更好的性能。
BTree索引它使用的数据结构是B+树。B+树每一个叶子接待都包含指向下一个叶子结点的指针。具体B+树的结构,可以参考数据结构相关书籍。
B-Tree索引能够加速数据的访问,因为存储引擎不再需要进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点中存放了指向子节点的指针,存储引擎根据中向下进行查找。通过比较叶子结点的中的值和要查找的值可以找到合适的指针进入下层子结点,这些指针定义了叶子结点中的值的下限和上限。最终搜索引擎要么找到该值,要么该记录不存在。
可以使用BTRee索引的数据类型:全键值,键值范围,键值前缀查找。
建立一个索引key(last_name,first_name,birth)
(1)全值匹配:全值匹配指的是和索引中的搜由来进行匹配,例如可用于查找姓名为Cuba Allen,出生日期为1969-09-01的人。
(2)匹配最左前缀:即使用索引的第一列,例如查找所有姓为Allen的人.
(3)匹配列前缀:用来匹配某一列的值的开头部分。例如用来查找所有以A为开头的姓的人。
(4)匹配范围值:例如查找所有姓在Allen和Barry之间的人。这里也只用了索引的第一列。
(5)精确匹配某一列并范围匹配另一列:例如匹配所有名为Allen,并且名字开头是字母K的人,即第一列全匹配,第二列范围匹配。
因为索引中的节点是有序的,所以除了按值查找之外,还可以用ORDER BY操作。
(1)如果不是按照索引的最左列开始查找,则无法使用索引。例如前面的无法查找名Bill的人。
(2)不能跳过索引中的列。例如前面的无法查找姓为Smith并且在某个特定生日的人。如果不指定first_name,则只能使用索引的第一列。
(3)如果查询中的某个列范围查找,则其右边所有列都不能使用索引优化查找。例如:WHERE last_name=”Smith” AND first_name like ”J%” AND birh=”1969-09-01”; first_name使用了范围查找,birth列就不能使用索引查找。
哈希索引是基于哈希表实现的,只有精确匹配索引所有列的查询才能有效。对于每一行,存储引擎会对所有的索引列计算一个哈希码,哈希码是一个较小的值。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存执行每个数据行的指针。
在MySQL中只有Memory引擎显示支持哈希索引。这也是Memory引擎表默认索引也是哈希索引,Memory引擎同时也支持BTree索引。Memory支持非唯一哈希索引,如果多个列的哈希值相同,索引会以链表的方式存放对个记录指针到同一个哈希记录中。
(1)哈希索引只存储哈希值和行指针,不存储字段值,索引不能使用索引中的 值来避免读取行。
(2)哈希索引并不是按照索引值顺序存储的,无法用于排序。
(3)哈希索引始终是使用索引列的全部内容来计算哈希值的,所以不支持部分 索引列匹配查找。例如,在(A,B)上建立哈希索引,如果只查询A列,则 无法使用哈希索引。
(4)哈希索引只支持等值查找不支持范围查找。
(5)访问哈希索引非常快,如果遇到哈希冲突的时候,存储引擎会遍历相应的 链表的所有行指针,逐行进行比较,直到找到所有符合条件的行。
(6)如果哈希冲突很多的话,索引维护操作的代价也会很高。例如,如果在哈 希冲突很多的列上建立索引,如果删除表中的一行,存储引擎需要遍历对应 哈希值的链表,找到对应的行并删除。
NDB集群引擎也支持唯一哈希索引。
InnoDB引擎有一个特殊功能:自适应哈希索引。当InnoDB发现某些索引列使用频繁时,会在B-Tree索引的基础上,会再创建一个哈希索引。是InnoDB的自动行为,用户无法控制。
如果存储引擎不支持哈希索引,我们可以自己创建哈希索引(伪哈希索引)。
例如:如果需要存储大量URL,并根据URL进行查找。如果使用的是B-Tree索引则,则存储内容就会非常大:
查询语句是:SELECT * FROM tb_url WHERE url=”http://csdn.com”;
如果自定义一个哈希索引:将原先的在url列上建立的索引删除,并且它在url列上增加一个新的索引url_crc,使用的是CRC32做哈希,就可以使用以下查询:
SELECT * FROM tb_url WHERE url=”http://csdn.com” AND url_crc = CRC32(”http://csdn.com”); 这样做性能就会非常高。
当使用哈希索引进行插叙时,必须在WHERE中包含产量值用来处理哈希冲突。SELECT * FROM tb_url WHERE url=”http://csdn.com” AND url_crc = CRC32(”http://csdn.com”); 如果有哈希冲突,可以通过url的值来筛选。
MyISAM引擎支持空间索引,可以用作地理数据存储。和B-Tree索引不同,这类索引无需前缀查询。空间索引会从所有维度来索引数据。查询时,可以有效的使用任意维度来组合查询。
全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。
(1)大大减少了服务器需要扫描的数据量。
(2)可以帮助服务器避免排序(B-Tree是按照顺序存储数据的)和临时表。
(3)所以可以将随机IO变为顺序IO。
如果查询中的列不是独立的列,MYSQL就不会使用索引。独立的列指索引列不能是表达式的一部分。例如:SELECT * FROM tb_student WHERE age+1=30;这个查询无法使用age列的索引。
有时候需要索引很长的字符列如url,这会让索引变得大且慢。之前介绍了一种自定义哈希索引。还可以有其他方法。
可以索引开始的部分字符,这样可以大大节约索引空间,从而提高效率。但这样也会降低索引的选择性。索引的选择性指:不重复的索引值和数据表的记录总数的比值。
当不需要考虑排序和分组时,将选择性最高的列放在前面通常是最好的。