MySQL执行删除操作时,是否会使用索引取决于删除语句的WHERE条件以及索引的匹配情况,联合索引由于包含多个字段,判断逻辑需要结合最左前缀匹配原则来分析。
删除操作使用索引的基本原理
MySQL的删除操作和查询操作类似,优化器会优先选择成本更低的执行方式。如果WHERE条件中的字段存在可用索引,且使用索引的成本低于全表扫描,就会选择使用索引定位要删除的记录,否则会进行全表扫描。
需要注意的是,即使使用了索引,删除操作仍然需要逐行定位记录后执行删除,索引的作用是减少需要扫描的数据量,而不是直接提升删除单条记录的速度。
联合索引的匹配规则
联合索引是按照索引字段的创建顺序依次排序的,只有符合最左前缀匹配原则的WHERE条件,才能有效使用联合索引。假设我们创建如下联合索引:
-- 创建测试表
CREATE TABLE user_order (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_status TINYINT NOT NULL,
create_time DATETIME NOT NULL,
INDEX idx_user_status_time (user_id, order_status, create_time)
);
-- 插入测试数据
INSERT INTO user_order (user_id, order_status, create_time) VALUES
(1, 0, '2024-01-01 10:00:00'),
(1, 1, '2024-01-02 11:00:00'),
(2, 0, '2024-01-01 12:00:00'),
(2, 1, '2024-01-03 13:00:00');
上述联合索引idx_user_status_time的字段顺序为user_id、order_status、create_time,匹配时必须满足最左前缀,也就是条件中需要包含左边的字段,才能使用索引。
命中联合索引的删除场景
以下删除语句的WHERE条件符合最左前缀原则,会使用联合索引:
- 条件包含最左字段user_id:
DELETE FROM user_order WHERE user_id = 1; - 条件包含user_id和order_status:
DELETE FROM user_order WHERE user_id = 1 AND order_status = 0; - 条件包含全部三个字段:
DELETE FROM user_order WHERE user_id = 1 AND order_status = 0 AND create_time < '2024-01-02 00:00:00';
无法命中联合索引的删除场景
以下删除语句的WHERE条件不符合最左前缀原则,不会使用联合索引:
- 条件不包含最左字段user_id:
DELETE FROM user_order WHERE order_status = 0; - 跳过中间字段:
DELETE FROM user_order WHERE user_id = 1 AND create_time < '2024-01-02 00:00:00';(此时只能使用索引的user_id部分,create_time条件无法利用索引)
判断删除操作是否使用索引的方法
可以通过EXPLAIN命令分析删除语句的执行计划,明确是否使用了索引。执行计划的key字段表示实际使用的索引,type字段表示访问类型,常见的有效类型包括ref、range、const等,如果是ALL则表示全表扫描。
以命中索引的删除语句为例,执行分析命令:
EXPLAIN DELETE FROM user_order WHERE user_id = 1 AND order_status = 0;
执行结果中,key字段会显示idx_user_status_time,type字段为ref,说明使用了联合索引。如果是无法命中索引的语句:
EXPLAIN DELETE FROM user_order WHERE order_status = 0;
执行结果中key字段为NULL,type字段为ALL,说明进行了全表扫描。
注意事项
即使WHERE条件符合索引使用规则,优化器也可能因为数据分布原因选择全表扫描,比如要删除的记录占全表的比例很高,此时全表扫描的成本反而更低。另外,删除操作使用索引时,如果删除大量数据,可能会导致索引维护成本上升,必要时可以先批量删除,或者删除后重建索引。
如果删除语句没有WHERE条件,一定会进行全表扫描,并且无法使用任何索引,执行前需要确认操作必要性,避免误删全表数据。