索引的创建与设计原则

一.索引的分类

从功能逻辑上来说,分为:普通索引、唯一索引、主键索引、全文索引。

  • 普通索引(NORMAL):不加任何限制条件,只为提高查询效率的索引。
  • 唯一索引(UNIQUE):限制该索引的值必须是唯一的,但允许有空值,一张表可以有多个唯一索引。
  • 主键索引:一种特殊的唯一索引,增加了不为空的约束,一张表最多只有一个主键索引。
  • 全文索引(FULLTEXT):利用分词技术等多种算法分析关键词的频率和重要性筛选,适合大型数据集。全文索引只能创建在 CHAR 、VARCHAR 或TEXT 类型及其系列类型的字段上查询数据量较大的字符串类型的字段时,使用全文索引可以提高查询速度。例如,表 student 的字段 information 是 TEXT 类型该字段包含了很多文字信息。在字段information上建立全文索引后,可以提高查询字段information的速度。随着大数据时代的到来,关系型数据库应对全文索引的需求已力不从心,逐渐被 solr、ElasticSearch 等专门的搜索引擎所替代

按照物理实现来分,分为:聚簇索引 和 非聚簇索引。

  • 聚簇索引:针对主键构建的索引,是一种数据存储方式,表的数据行都存放在索引树的叶子页中。
  • 非聚簇索引:针对非主键构建的索引,它不保存完整记录,且按照索引列排序。

按照作用字段个数来分,分成:单列索引 和 联合索引。

  • 单例索引:在表中的单个字段上创建索引。单列索引只根据该字段进行索引。单列索引可以是普通索引,也可以是唯一性索引,还可以是全文索引。只要保证该索引只对应一个字段即可。一个表可以有多个单列索引。
  • 多列索引:在表的 多个字段组合上创建一个索引。该索引指向创建时对应的多个字段,可以通过这几个字段进行查询,但是只有查询条件中使用了这些字段中的第一个字段时才会被使用。例如,在表中的字段id、name和gender上建立一个多列索引 idx_id_name_gender,只有在查询条件中使用了字段id时该索引才会被使用。使用组合索引时遵循最左前缀集合。

不同的存储引擎支持的索引类型也不一样

  • InnoDB:支持 B+ tree、Full-text 等索引,不支持 Hash 索引
  • MyISAM:支持 B+ tree、Full-text 等索引,不支持 Hash 索引
  • Memory:支持 B+ tree、Hash 等索引,不支持 Full-text 索引

二.索引的设计原则

适合创建索引的情况

1.频繁作为 WHERE 条件的字段

某个字段在SELECT、UPDATE 或 DELETE 语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。

2.经常 GROUP BY 和 ORDER BY 的列

索引就是让数据按照某种顺序进行存储或检索,因此当我们使用 GROUP BY 对数据进行分组查询,或者使用ORDER BY对数据进行排序的时候,就需要对 分组 或者 排序 的字段进行索引。如果需要索引的列有多个,那么可以在这些列上建立 组合索引。

  • 当需要索引的列只有一个时,比方说 通过 student_id 来 GROUP BY
SELECT student_id, COUNT(*) AS num 
FROM student_info 
GROUP BY student_id

我们可以给 student_id 加上索引,提高查询速率。同样,如果是 ORDER BY,也可以给相应字段加上索引。

  • 当需要索引的列有多个时,比方说同时有 GROUP BY 和 ORDER BY:
SELECT student_id, COUNT(*) AS num FROM student_info 
GROUP BY student_id 
ORDER BY create_time DESC 

如果分别给 student_id 、create_time 建立索引的话,会发现实际上只会用到 student_id 的索引,并且 执行速度较慢。因为多个单列索引在多条件查询时 只会生效一个索引 (MSOL 会选择其中一个限制最严格的作为索引,所以在多条件联合查询的时候最好创建联合索引。

正常来说我们应该根据SQL执行的顺序来创建联合索引,这里由于group by先执行,所以我们应该创建的是 (student_id,create_time) 的联合索引,而非 (create_time,student_id)。这里提一下,如果(create_time,student_id) 顺序的联合索引 和 student_id 单列索引 共存的话还是会走student_id 单列索引,因为group by先执行。

3.经常DISTINCT的列

有时候我们需要对某个字段进行去重,使用 DISTINCT,那么对这个字段创建索引,也会提升查询效率

4.多表 JOIN 连接操作时,创建索引注意事项

  1. 首先,连接表的数量尽量不要超过 3 张,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率。
  2. 其次,对 WHERE 条件创建索引,因为WHERE才是对数据条件的过滤。如果在数据量非常大的情况下,没有WHERE条件过滤是非常可怕的。
  3. 最后,对用于连接的字段创建索引。并且该字段在多张表中的类型必须一致,如果用上函数转化的话,索引会失效。

5.列的数据类型应该尽量小

我们这里所说的 类型大小 指的就是该类型表示的数据范围的大小。

  • 数据类型越小,在查询时进行的比较操作越快
  • 数据类型越小,索引占用的存储空间就越少,在一个数据页内就可以放下更多的记录,从而减少磁盘 I/O 带来的性能损耗,也就意味着可以把更多的数据页缓存在内存中,从而加快读写效率

这个建议对于表的 主键来说更加适用,因为不仅是聚簇索引中会存储主键值,其他所有的二级索引的节点处都会存储一份记录的主键值,如果主键使用更小的数据类型,也就意味着节省更多的存储空间和更高效的 I/O

6.使用字符串前缀创建索引

假设我们的字符串很长,那存储一个字符串就需要占用很大的存储空间。在我们需要为这个字符串列建立索引时,会出现两个问题:

  • 字符串比较速度慢
  • 占用的存储空间大

我们可以通过截取字段的前面一部分内容建立索引,这个就叫前缀索引。这样在查找记录时虽然不能精确的定位到记录的位置,但是能定位到相应前缀所在的位置,然后根据前缀相同的记录的主键值回表查询完整的字符串值。既节约空间,又减少了字符串的比较时间。

计算截取不同长度的散列度(选择性)

如检测 截取地址长度 的散列度:

select count(distinct left(列名,索引长度)) / count(*) from 表;

越接近1当然效果越好,说明散列度高

7.区分度高(散列性高)的列适合作为索引

列的基数 指的是某一列中不重复数据的个数。比方说某个列包含值 2,5,8,2,5,8,2,5,8,虽然有9条记录,但该列的基数却是3。也就是说,在记录行数一定的情况下,列的基数越大,该列中的值越分散;列的基数越小,该列中的值越集中。

这个列的基数指标非常重要,直接影响我们是否能有效的利用索引。因为索引的价值是帮助你快速定位,如果需要定位的数据有很多,那么索引就失去了它的使用价值,比如通常情况下的性别字段。

可以使用公式计算区分度,越接近1越好,一般超过33%就算是比较高效的索引了,所以有唯一性字段适合建立索引

select count(distinct 列名)/count(*) from 表名

8.使用最频繁的列放到联合索引的左侧

这样也可以较少的建立一些索引。同时,由于"最左前缀原则",可以增加联合索引的使用率。

9.在多个字段都要创建索引的情况下,联合索引优于单值索引

不适合创建索引的情况

1.数据量小的表最好不要使用索引

如果表记录太少,比如少于 1000 个,那么是不需要创建索引的。表记录太少,是否创建索引对查询效率的影响并不大。甚至说,查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果。

2.避免对经常更新的表创建过多的索引

  • 频繁更新的字段不一定要创建索引,因为更新数据的时候,索引也要跟着更新,如果索引太多,更新的时候会造成服务器压力,从而影响效率。
  • 避免对经常更新的表创建过多的索引,并且索引中的列尽可能少。此时虽然提高了查询速度,同时也会降低更新表的速度。

3.有大量重复数据的列上不要建立索引

在条件表达式中经常用到的不同值较多的列上建立索引,但字段中如果有大量重复数据,也不用创建索引。比如学生表中的性别字段,只有男和女两种值,因此无需建立索引。如果建立索引,不但不会提高查询效率,反而会严重降低数据更新速度。

三.限制索引的数量

在实际工作中,我们也需要注意平衡,索引的数目不是越多越好。我们需要限制每张表上的索引数量,最好单张表索引数量不超过6个。原因:

  1. 每个索引都需要占用 磁盘空间,索引越多,需要的磁盘空间就越大。
  2. 索引会影响INSERT、DELETE、UPDATE等语句的性能,因为表中的数据更改的同时,索引也会进行调整和更新,会造成负担。
  3. 优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的 索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,会增加MySQL优化器生成执行计划时间,降低查询性能.

你可能感兴趣的:(数据库,数据库)