视频讲解:索引干扰导致索引失效如何解决_哔哩哔哩_bilibili
1 场景说明
表tb_order有订单状态order_status和创建时间create_time的索引。
现在业务的需求是,查询半年内,已支付订单状态的总数。SQL语句如下:
SELECT
COUNT(1)
FROM
tb_order od
WHERE od.`order_status` = 2
AND od.`create_time` > '2024-03-07' AND od.`create_time` < '2024-09-07';
执行计划如下:
问题描述:
高效索引create_time没有使用上,order_status单值索引影响了高效索引的使用,如何解决这个问题?
2 create_time失效原因以及两种处理方案讲解
视频详细讲解索引干扰导致索引失效问题的解决方案:索引干扰导致索引失效如何解决_哔哩哔哩_bilibili
3 少量固定值作为单值索引的弊端
使用订单状态值作为单值索引可能会遇到以下几种情况和潜在的弊端:
-
选择性差:
- 订单状态通常只有几个不同的值(如“待支付”、“已支付”、“已发货”、“已完成”等)。这样的字段选择性较低,意味着索引中的大多数值都是重复的。对于查询优化器来说,这样的索引可能并不比全表扫描更有效率。
-
索引利用率低:
- 如果应用程序查询模式主要是基于订单ID或其他唯一标识符进行查询,那么在订单状态上创建索引并不会提高这些查询的性能。相反,如果查询主要涉及订单状态,那么这种索引可能会有用。
-
更新开销:
- 订单状态的变化会触发索引更新。每次状态改变时,都会产生额外的写操作,增加了数据库的负载。如果订单状态频繁变更,这种开销可能会变得显著。
-
并发问题:
- 在高并发环境下,如果多个事务同时尝试更新同一个订单的状态,可能会导致索引锁的竞争,从而降低系统的整体吞吐量。
-
存储空间浪费:
- 为一个选择性差的字段创建索引会占用额外的空间,而这些空间可能没有得到充分利用,尤其是在B树索引中,每个不同的值都会占用一定的空间。
-
查询优化器的行为:
- MySQL的查询优化器可能不会优先考虑使用选择性差的索引来执行查询。在某些情况下,即使存在索引,优化器也可能会选择全表扫描或者其他更高效的访问路径。
4 没有开启查询缓存,为什么第二次查询比第一次查询快了
即使没有开启查询缓存(Query Cache),第二次查询仍然可能比第一次查询快,这是因为数据库管理系统(DBMS)内部有多种机制可以提高查询性能,包括但不限于以下几种情况:
-
缓冲池(Buffer Pool):大多数关系型数据库都有一个缓冲池,用于缓存最近访问的数据页。当查询再次执行时,如果所需的数据已经存在于缓冲池中,则不需要从磁盘读取,这样可以显著加快查询速度。
-
读取缓存(Read Cache):操作系统通常也有自己的文件系统缓存,会将最近读取的数据存储在内存中。如果查询的数据已经在操作系统缓存中,那么第二次查询可以直接从内存中读取数据,而不需要访问磁盘。
-
查询解析与优化:第一次执行查询时,数据库需要解析SQL语句并生成执行计划。这个过程可能比较耗时。第二次执行相同的查询时,数据库可以直接重用已有的执行计划,减少了解析和优化的时间。
-
索引缓存:索引本身也可能被缓存在内存中。当索引被首次使用时,其部分或全部可能被加载到内存中,后续查询可以直接利用缓存的索引来定位数据,从而加速查询。
-
连接池:如果是在应用层使用了数据库连接池,那么建立数据库连接的时间可以忽略不计,因为连接已经被复用了。
-
统计信息:一些数据库系统会在第一次执行查询时收集统计信息,这些信息在第二次执行时会被利用来更好地优化查询。
因此,即使没有启用查询缓存,由于上述机制的存在,第二次查询仍然可以更快。如果你想要验证这些假设,可以通过监控工具来检查数据库的缓存命中率、执行计划以及其他性能指标,以确定具体的原因。此外,也可以通过关闭或限制内存缓冲池大小来观察查询性能的变化,从而进一步确认是哪些因素在起作用。