5个坑?1个法则!数据库索引的最左前缀魔法揭秘:从10秒到0.1秒的逆袭!

关注墨瑾轩,带你探索编程的奥秘!
超萌技术攻略,轻松晋级编程高手
技术宝库已备好,就等你来挖掘
订阅墨瑾轩,智趣学习不孤单
即刻启航,编程之旅更有趣

在这里插入图片描述在这里插入图片描述

** 最左前缀法则——数据库的“最左”情结**
问题1:索引明明存在,为什么查询还是慢到怀疑人生?

案例

-- 创建用户表  
CREATE TABLE users (  
    id INT PRIMARY KEY,  
    name VARCHAR(50),  
    age INT,  
    email VARCHAR(100)  
);  

-- 创建联合索引(name, age, email)  
CREATE INDEX idx_name_age_email ON users(name, age, email);  

-- 错误查询:跳过最左列"name"  
SELECT * FROM users WHERE age = 30 AND email = '[email protected]';  

-- 正确查询:包含最左列"name"  
SELECT * FROM users WHERE name = '张三' AND age = 30;  

执行计划对比

-- 错误查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE age = 30 AND email = '[email protected]';  
-- type: ALL(全表扫描!索引完全没用!)  

-- 正确查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name = '张三' AND age = 30;  
-- type: ref(使用索引!)  

原因

  • 最左前缀法则:联合索引必须从最左列开始匹配,且中间不能跳过字段!
  • 索引失效:跳过name直接查询age,相当于告诉数据库“我不要按字典顺序找,你随便翻页”,索引自然失效。

问题2:模糊查询为什么让索引“破功”?

案例

-- 错误查询:模糊查询%在最左  
SELECT * FROM users WHERE name LIKE '%三';  

-- 正确查询:模糊查询%在右侧  
SELECT * FROM users WHERE name LIKE '张%';  

执行计划对比

-- 错误查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name LIKE '%三';  
-- type: ALL(全表扫描!索引失效!)  

-- 正确查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name LIKE '张%';  
-- type: ref(使用索引!)  

原因

  • 索引的“偏心”真相:联合索引的字段是按顺序排列的,name LIKE '张%'能利用索引的前缀匹配,而name LIKE '%三'像“翻书找某页最后几个字”,无法定位。

问题3:范围查询为什么让索引“半途而废”?

案例

-- 创建联合索引(name, age, email)  
CREATE INDEX idx_name_age_email ON users(name, age, email);  

-- 错误查询:范围查询在中间字段  
SELECT * FROM users WHERE name = '张三' AND age > 25;  

-- 正确查询:范围查询在最后字段  
SELECT * FROM users WHERE name = '张三' AND email LIKE 'test%';  

执行计划对比

-- 错误查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name = '张三' AND age > 25;  
-- key_len: 43(只用了name字段)  

-- 正确查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name = '张三' AND email LIKE 'test%';  
-- key_len: 95(用到了name、age、email全字段)  

原因

  • 范围查询的“破坏力”:当age字段用>时,数据库无法确定后续字段的范围,导致email字段的索引失效。
  • 顺序决定一切:范围查询必须放在最后才能最大化索引利用率!

问题4:为什么多条件查询反而更慢?

案例

-- 错误查询:多条件但跳过最左列  
SELECT * FROM users WHERE age = 30 AND email = '[email protected]';  

-- 正确查询:按索引顺序添加条件  
SELECT * FROM users WHERE name = '张三' AND age = 30 AND email = '[email protected]';  

执行计划对比

-- 错误查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE age = 30 AND email = '[email protected]';  
-- type: ALL(全表扫描!)  

-- 正确查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name = '张三' AND age = 30 AND email = '[email protected]';  
-- type: ref(使用索引!)  

原因

  • “贪心”查询的代价:即使条件多,但跳过最左列,索引依然失效!
  • 最左优先原则:条件必须按索引顺序依次出现,才能逐步缩小搜索范围。

问题5:为什么覆盖索引比普通索引更快?

案例

-- 错误查询:SELECT * 导致回表  
SELECT * FROM users WHERE name = '张三';  

-- 正确查询:覆盖索引(只查询索引字段)  
SELECT name, age FROM users WHERE name = '张三';  

执行计划对比

-- 错误查询的EXPLAIN结果  
EXPLAIN SELECT * FROM users WHERE name = '张三';  
-- Extra: Using where; Using index (需要回表查询其他字段)  

-- 正确查询的EXPLAIN结果  
EXPLAIN SELECT name, age FROM users WHERE name = '张三';  
-- Extra: Using index (直接从索引中获取数据,无需回表)  

原因

  • 覆盖索引的“魔法”:如果查询字段完全包含在索引中,数据库直接从索引中读取数据,避免回表,速度翻倍!

终极法则:最左前缀的“通关秘籍”

公式

有效查询条件 = 最左列 + 第二列(可选) + 第三列(可选)...  
无效查询条件 = 跳过最左列 → 索引失效!  

实战步骤

  1. 创建联合索引
    CREATE INDEX idx_name_age_email ON users(name, age, email);  
    
  2. 按索引顺序写查询
    -- 正确写法  
    SELECT name, age FROM users  
    WHERE name = '张三' AND age BETWEEN 20 AND 30;  
    
    -- 错误写法(跳过name)  
    SELECT * FROM users WHERE age = 30; -- 索引失效!  
    
  3. 善用覆盖索引
    -- 覆盖索引查询(无需回表)  
    SELECT name, age FROM users WHERE name = '张三';  
    

工具对比表:5大坑点一目了然
坑点类型 错误操作 优化后效果 解决方案
跳过最左列 查询条件不包含name 索引失效,全表扫描 修正查询条件,包含name
模糊查询%在左 name LIKE ‘%三’ 索引失效,全表扫描 重写查询为name LIKE ‘张%’
范围查询在中间 WHERE name = ‘张三’ AND age > 25 只用到name字段,email字段无效 将范围查询放在最后
多条件跳过索引 WHERE age = 30 AND email = ‘test’ 索引完全失效 按索引顺序添加条件
**SELECT *** SELECT * FROM users WHERE name… 需要回表查询,速度慢 使用覆盖索引(只选索引字段)

你可能感兴趣的:(数据库学习,数据库,oracle,sql)