索引以及Mysql中的索引
一、什么是索引
索引是表的目录,会保存在额外的文件中,针对表中的指定列建立,专门用于帮助用户快速查询数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获取即可。在查找数据库内容之前可以先在索引中查询,快速定位查询数据。用在where,like,having等查询语句。
二、建立索引的列
1、越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,一个磁盘页可以放更多的数据,查询效率更高。
2、简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。
3、尽量避免NULL:应该指定列为NOT nuLL,在MySQL中, 含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂
三、什么场合不适合创建索引
1、对于那些在查询中很少使用的列。既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
2、列取值比较集中的列。比如性别列,只有男女两种取值,结果集合就是相当于全表查询了,就算加了索引也不能明显加快索引速度。
3、blob,clob等类型的数据列。这些列的数据量要么相当大,要么取值很少。
4、对于列的修改操作远多于查找操作时。因为建立索引后会提高查找性能,降低修改性能;没有索引时,虽然查找效率较低,但是修改性能高,因为在修改数据时,需要同步修改数据表和索引,增加了工作量。
四、什么场合适合创建索引
1、表的主键、外键必须有索引(主键索引不需要手动建立,本身会添加);外键也是唯一的,而且经常会用来查询。
2、数据量1000条、数据总量也超过了MySQL服务器上的内存总量时
3、经常与其他表进行left join ,inner join,right join 连接的表,在连接字段上应该建立索引;经常连接查询,需要有索引
4、经常出现在Where子句中的字段,加快判断速度,特别是大表的字段,应该建立索引,,一般用在select ……where f1 and f2 ,我们在f1或者f2上建立索引是没用的。只 有两个使用联合索引才能有用。
5、经常用到 order by 排序的列上,因为索引已经排序。
6、经常用在范围内搜索的列上 between and 创建索引,因为索引已经排序了,其指定的范围是连续的。
7、高并发条件下倾向组合索引;
8、用于聚合函数的列可以建立索引,例如使用了max(column_1)或者count(column_1)时的column_1就需要建立索引
五、索引失效的情况
1、在查询条件中使用IS NULL或者IS NOT NULL会导致索引失效。
2、LIKE操作中,'%aaa%'索引会失效,但是‘aaa%’可以使用索引。
3、在索引的列上使用函数会使索引失效,比如DATADIFF,LOWER等。
4、负向查询(not , not in, not like, <>, != ,!>,!< ) 不会使用索引。
5、类型不一致会导致失效,比如字符串不加单引号会导致索引失效,比如字段email是字符串类型的,使用WHERE email=99999 则会导致失败,应该改为WHERE email='99999'。
6、使用OR连接多个条件,需要每个条件都加上索引,否则索引失效,或者改为两次查询UNION ALL更为高效;使用and时,必须使用组合索引,且满足前缀原则。
7、当order by 字段出现在where条件中时,才会利用索引而无需排序操作。
六、索引优缺点
优点:减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序;
缺点:索引本身也是表,因此会占用存储空间,一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表;一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
七、使用索引时的分类
1,普通索引:仅加速查询 最基本的索引,没有任何限制,是我们大多数情况下使用到的索引。
ALTER TABLE 'table_name' ADD INDEX index_name('col');
2、唯一索引:与普通索引类型,不同的是:加速查询 + 列值唯一(可以有null)
ALTER TABLE 'table_name' ADD UNIQUE index_name('col');
3、主键索引:即主索引,根据主键pk_clolum(length)建立索引,不允许重复,不允许空值;
ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col');
4、全文索引:用大文本对象的列构建的索引(下一部分会讲解)
ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col');
可以在创建表的时候创建索引,然后再插入数据;也可以在已经有数据的表上添加索引。
*(后添加索引更快)对于较大的数据集,把数据添加到一个没有FULLTEXT索引的表,然后添加FULLTEXT索引的速度比把数据添加到一个已经有FULLTEXT索引的表快。
*5.6版本前的MySQL自带的全文索引只能用于MyISAM存储引擎,如果是其它数据引擎,那么全文索引不会生效。5.6版本之后InnoDB存储引擎开始支持全文索引
*在MySQL中,全文索引只对英文有用,目前对中文还不支持。5.7版本之后通过使用ngram插件开始支持中文。
*在MySQL中,如果检索的字符串太短则无法检索得到预期的结果,检索的字符串长度至少为4字节。
5、组合索引:将几个列作为一条索引进行检索,使用最左匹配原则。
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
最左前缀原则:把最常用作为检索或排序的列放在最左,依次递减,组合索引相当于建立了col1, col1 col2, col1 col2 col3三个索引,而col2或者col3是不能使用索引的。建立组合索引时要思考几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立组合索引;否则考虑单字段索引;
八、索引实现原理分类
MySQL支持诸多引擎,而各种引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,
BTree索引:参见上一篇文章。
B+Tree索引:参见上一篇文章。
哈希索引:memory引擎支持哈希索引,引用索引列的值计算该值的hashCode,然后在hashCode相应的位置存执该值所在行数据的物理位置,希索引不支持范围查找和排 序的功能。
全文索引:FULLTEXT(全文)索引,仅可用于MyISAM和InnoDB,针对较大的数据,生成全文索引非常的消耗时间和空间,但是好于使用普通索引的LIKE %word%。在 生成FULLTEXT索引时,会为文本生成一份单词的清单,在索引时及根据这个单词清单来索引。
用户为表建立索引后,mysql一般通过算法生成一个索引文件,存储在磁盘中,进行查询操作时会利用索引文件提高查询效率。
九、聚簇索引与非聚簇索引
上一节分析了不同的存储引擎会使用不同的数据结构来存储索引,那引擎是怎么利用索引定位到所查的数据行的呢,可以分为两种方式,聚簇索引和非聚簇索引。
MySQL中最常见的两种存储引擎分别是MyISAM和InnoDB,分别实现了非聚簇索引和聚簇索引。
先明确两个概念:“主索引”和“辅助索引”,在索引的分类中,我们可以按照索引的键是否为主键来分为“主索引”和“辅助索引”,使用主键键值建立的索引称为“主索引”,其它的称为“辅助索引”。因此主索引只能有一个,辅助索引可以有很多个。
MyISAM——非聚簇索引
- 数据表和索引表是分开存储。
- 主索引和辅助索引几乎是一样的,只是主索引不允许重复,不允许空值,他们的叶子结点的key都存储指向数据列的物理地址。
- 数据是根据数据的插入顺序保存。非聚簇索引更适合单个数据的查询???不懂。
*最开始我一直不懂既然非聚簇索引的主索引和辅助索引指向相同的内容,为什么还要辅助索引这个东西呢,后来才明白索引不就是用来查询的吗,用在那些地方呢,不就是WHERE和ORDER BY 语句后面吗,那么如果查询的条件不是主键怎么办呢,这个时候就需要辅助索引了。
InnoDB——聚簇索引
- 数据和主键索引存储在一起。
- 主索引的叶子结点存储的是对应的数据本身,辅助索引的叶子结点存储的是对应的数据的主键键值(根据主键键值再根据主键索引查找数据)。因此主键的值长度越小越好,类型越简单越好。
- 数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂,严重影响性能。
- 在InnoDB中,如果只需要查找索引的列,就尽量不要加入其它的列,这样会提高查询效率???不懂。
*使用主索引的时候,更适合使用聚簇索引,因为聚簇索引只需要查找一次,而非聚簇索引在查到数据的地址后,还要进行一次I/O查找数据。
*因为聚簇辅助索引存储的是主键的键值,因此可以在数据行移动或者页分裂的时候不用维护辅助索引,降低成本。但是由于主索引存储的是数据本身,因此聚簇索引会占用更多的空间。
*聚簇索引在插入新数据的时候比非聚簇索引慢很多,因为插入新数据时需要检测主键是否重复,这需要遍历主索引的所有叶节点,而非聚簇索引的叶节点保存的是数据地址,占用空间少,因此索引文件分布集中,查询的时候I/O更少,但聚簇索引的主索引中存储的是数据本身,数据占用空间大,分布范围更大,可能占用好多的扇区,因此需要更多次I/O才能遍历完毕。
下图可以形象的说明聚簇索引和非聚簇索引的区别
此外MyISAM和innoDB的区别总结如下:
总结如下:
- InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
- MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
此外,Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
十、索引的优化
1、最左前缀
索引的最左前缀和和B+Tree中的“最左前缀原理”有关,举例来说就是如果设置了组合索引<col1,col2,col3>那么以下3中情况可以使用索引:col1,<col1,col2>,<col1,col2,col3>,其它的列,比如<col2,col3>,<col1,col3>,col2,col3等等都是不能使用索引的。
根据最左前缀原则,我们一般把排序分组频率最高的列放在最左边,以此类推。
2、带索引的模糊查询优化
在上面已经提到,使用LIKE进行模糊查询的时候,'%aaa%'不会使用索引,也就是索引会失效。如果是这种情况,只能使用全文索引来进行优化(上文有讲到)。
3、为检索的条件构建全文索引,然后使用
SELECT * FROM tablename MATCH(index_colum) ANGAINST(‘word’);
4、使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
参考文献: