关注墨瑾轩,带你探索编程的奥秘!
超萌技术攻略,轻松晋级编程高手
技术宝库已备好,就等你来挖掘
订阅墨瑾轩,智趣学习不孤单
即刻启航,编程之旅更有趣
案例:
-- 创建用户表
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
,相当于告诉数据库“我不要按字典顺序找,你随便翻页”,索引自然失效。案例:
-- 错误查询:模糊查询%在最左
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 '%三'
像“翻书找某页最后几个字”,无法定位。案例:
-- 创建联合索引(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
字段的索引失效。案例:
-- 错误查询:多条件但跳过最左列
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(使用索引!)
原因:
案例:
-- 错误查询: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 (直接从索引中获取数据,无需回表)
原因:
公式:
有效查询条件 = 最左列 + 第二列(可选) + 第三列(可选)...
无效查询条件 = 跳过最左列 → 索引失效!
实战步骤:
CREATE INDEX idx_name_age_email ON users(name, age, email);
-- 正确写法
SELECT name, age FROM users
WHERE name = '张三' AND age BETWEEN 20 AND 30;
-- 错误写法(跳过name)
SELECT * FROM users WHERE age = 30; -- 索引失效!
-- 覆盖索引查询(无需回表)
SELECT name, age FROM users WHERE name = '张三';
坑点类型 | 错误操作 | 优化后效果 | 解决方案 |
---|---|---|---|
跳过最左列 | 查询条件不包含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… | 需要回表查询,速度慢 | 使用覆盖索引(只选索引字段) |