索引的使用场景和优化

目录

  • 第一章、索引的优势和劣势
    • 1.1)优势
    • 1.2)劣势
  • 第二章、创建索引的场景
    • 2.1)应创建索引的字段
    • 2.2)不应创建索引的字段
  • 第三章、索引优化
    • 3.1)索引失效
    • 3.2)索引优化
    • 3.3)使用索引优化排序

友情提醒:

先看文章目录,大致了解文章知识点结构,点击文章目录可直接跳转到文章指定位置。有用记得关注

第一章、索引的优势和劣势

1.1)优势

1、通过创建索引,可以再查询的过程中,提高系统的性能
2、通过创建唯一性索引,可以保持数据库表中每一行数据的唯一性
3、在使用分组和排序子句进行数据检索时,可以减少查询中分组和排序的时间

1.2)劣势

1、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加;缺点是在插入、更新和删除记录时,需要同时修改索引,因此,索引越多,插入、更新和删除记录的速度就越慢。
2、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大;如果表中数据量巨大,索引数量多,索引文件可能比数据本身的文件会更快到达硬件限制。
3、聚簇数据最大限度地提高了 I/O 密集型应用的性能,但如果数据全部都放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了。

第二章、创建索引的场景

2.1)应创建索引的字段

1、作为主键必须有索引;(主键)
2、经常用在连接的列上,主要是一些外键,可以加快连接的速度(外键)
3、经常需要搜索的列上,加快搜索的速度; (需搜索)
4、经常需要排序的列上创建索引,利用索引已经排序,加快排序查询时间;(需排序)
5、 经常需要根据范围搜索的列上,因为索引已经排序,其指定的范围是连续的;(范围)
6、经常使用在WHERE子句中的列上,加快条件的判断速度。(where)
7、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;

2.2)不应创建索引的字段

1、查询中很少用到的列,有索引并不能提高查询速度。
2、取值很少的列,比如数据表中的性别列
3、text, image和bit数据类型的列,这些列的数据量要么相当大,要么取值很少。
4、被频繁更新的列,会提高搜索性能,但是会降低修改性能

第三章、索引优化

3.1)索引失效

①索引列作为表达式的一部分或者函数参数,那么索引会失效。例如,下面这个查询无法使用 actor_ id 列的索引:

SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

只有将上述语句修改为如下等价形式,才能够享受到 MySQL 的索引查询优化:

SELECT actor_id FROM sakila.actor WHERE actor_id = 4;

②不符合最左匹配原则,例如定义了 (a,b,c) 联合索引,相当于构造了 (a)、(a,b)、(a,b,c) 索引。如果要使 c 索引实际工作,那么必须在 WHERE 中同时加入 a、b 字段的条件,顺序无所谓。对于 b,则必须加入 a。而 a 索引可以单独出现并工作。

③查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。例如有查询 WHERE last_name=‘Smith’ AND first_ name LIKE ‘%JJ’ AND dob =’ 1976-12-23’,这个查询只能使用索引的前两列,因为这里 LIKE 是一个范围条件。
其他常见的范围查找有:通过 <,>,<= ,\ >=,\ between,!=,或者 <> 操作符做比较。它们都是导致索引失效。
注意事项:IN() 不是范围匹配,而是多个等值匹配,因此并不会导致索引失效。

④WHERE 子句的查询条件里使用了比较操作符 LIKE 和 REGEXP,第一个字符不是通配符的情况下才能使用索引。比如说,如果查询条件是 LIKE ‘abc%’,MySQL 将使用索引(虽然最终会导致后续索引失效);如果条件是 LIKE ‘%abc’,MYSQL 将不使用索引。

⑤ 如果 WHERE 子句带有 or 且有字段不属于索引,那么即使其中带索引的字段也不会使用。

⑥使用了select*,大概率会查询非索引列的数据就无法使用覆盖索引了

⑦对查询结果排序时使用order by,不符合索引结构的顺序。

⑧索引列值为null,致COUNT(*)不能走索引
查询诸如SELECT COUNT(*) FROM Table 的时候,因为HASHSET中不能存储空值的,所以优化器不会走索引。
⑨not in 和 notexists使所有失效 而IN() 和exists不是范围匹配,而是多个等值匹配,因此并不会导致索引失效。

⑩字段类型不同 ,比如你的索引字段是varchar型,但是你搜索条件却是 userid=333,那这样索引不生效。

3.2)索引优化

①不要让字段的默认值为NULL
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。
②注意避免冗余索引尽可能的考虑建立联合索引而不是单列索引
而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的。
③使用短索引
如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引,考虑在字符串类型的字段上使用前缀索引代替普通索引
④索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;如果需要最好给这些列创建复合索引。
⑤like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,要注意like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
⑥不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。

⑦注意范围查询无法使用索引
如<,>,<= ,\ >=,\ between,!=,或者 <>以及某些时候的like(以通配符%或_开头的情形)。

3.3)使用索引优化排序

如果有排序的需求,我们只需要order by,底层实现起来整体上来说,有两种不同的思路:

filesort排序介绍
有时候我们也将之称为文件排序,数据库在执行过程中,数据量比较小的时候先将满足条件的数据全部读出来,放入内存sort_buffer中执行快排,如果临时数据量比内存sort_buffer 大, 就要把数据放入临时文件,然后做外部排序,这种操作就是 filesort。只有当在内存中无法完成排序的时候,才会用到磁盘文件。

索引排序
给需要排序的字段加上索引,由于 InnoDB 中的索引是按照 B+Tree 的形式将数据组织在一起的,B+Tree 中数据本身就是有序的,所以如果能够利用好索引,排序的事情就会事半功倍。

索引排序原理
B+ 树叶子节点的关键字从小到大有序排列,所有节点关键字是按递增次序排列,并遵循左小右大原则;就是说如果有重复元素,父节点 20,子节点 20,那么子节点应当位于右侧,即:子节点<父节点≤右子节点
只有当索引的顺序和 order by 子句的顺序完全一致,并且所有列的排序方向也都一致的情况下,MySQL 才能通过索引来对结果进行排序,同时,如果是联合索引,order by 子句也需要满足最左匹配原则。

符合索引结构的情况会进行索引排序
InnoDB 索引树以任意一个叶节点为起始点,可以向左或向右遍历;如果语句需要的 order by 顺序刚好可以利用索引树的单向遍历,就可以避免排序操作。

为了便于说明,创建一个简单的表,这个表里,除了主键索引 id 外,还有一个联合索引 ab。
①单字段倒序排序:将这个表的数据,按照 a 的大小倒序返回。因为这次排序符合索引结构的存储情况,所以会进行索引排序而不是filesort排序

SELECT * FROM t WHERE a >0 ORDER BY a DESC;

语句的执行流程:
1、从索引 ab 上,取最右的一个记录,取出主键值 ID_Z;
2、根据 ID_Z 到主键索引上取整行记录,作为结果集的第一行;
3、在索引 ab 上取上一个记录的左边相邻的记录;
4、每次取到主键 id 值,再到主键索引上取到整行记录,添加到结果集的下一行;
重复步骤 3、4,直到遍历完整个索引。

②组合字段倒序排序:按照 a 值倒序,当 a 的值相同时按照 b 值倒序。因为这次排序符合索引结构的存储情况,所以会进行索引排序同样不需要filesort排序

SELECT * FROM t WHERE a >1 AND b >1 ORDER BY a desc,b desc;

③组合字段正序排序:显然,这个语句也是不需要排序的,理由和上面一样,只需要先取 ab 索引树最左边的节点,然后向右遍历即可。

SELECT * FROM t WHERE a >1 AND b >1 ORDER BY a,b;

不符合索引结构的情况会进行filesort排序
按照a值正序,对于相同的a值,b值需要倒序排序。
与索引的存储情况不同,因此只能选择使用filesort排序操作。

select * from t order by a, b desc;

解决方式:既然不符合索引结构会进行filesort排序那么我们改变索引存储结构不就好了嘛?
在8.0版本中支持了这个功能,官方名称是Descending Indexes。在8.0版本中,我们可以把索引ab的定义做个修改。这样从左到右遍历这个索引的时候,就刚好满足a正序,然后b逆序的要求。
Descending Indexes可以避免这种情况下的排序操作,语句的执行性能自然就提升了。

create table `t` (
    `id` int(11) NOT NULL,
    `a`  int(11) NOT NULL,
    `b`  int(11) NOT NULL,
    `c`  int(11) NOT NULL,
    primary key (`id`),
    key `ab` (`a`, `b` desc) 
) engine = InnoDB;

ORDER BY 语句也使用索引最左前缀原则;
比如 (a,b) 联合索引下,ORDER BY a 、ORDER BY a,b 都是符合要求的,但是如果 ORDER BY b 或者 ORDER BY b,a 这种情况都是不符合要求的。

你可能感兴趣的:(数据库学习心得与问题记录,java,数据库,jvm)