云计算百科
云计算领域专业知识百科平台

php方案 索引失效场景

MySQL 索引失效场景完整示例

============ 1. 函数操作导致失效 ============
失效案例
SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01';
SELECT * FROM users WHERE SUBSTRING(name, 1, 1) = '张';
SELECT * FROM products WHERE UPPER(name) = 'IPHONE';

优化方案
SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2024-01-02';
SELECT * FROM users WHERE name LIKE '张%';
SELECT * FROM products WHERE name = 'iPhone'; 使用 COLLATE 不区分大小写

============ 2. 隐式类型转换 ============
失效案例(phone 是 VARCHAR
SELECT * FROM users WHERE phone = 13800138000;
SELECT * FROM orders WHERE order_no = 202401010001;

优化方案
SELECT * FROM users WHERE phone = '13800138000';
SELECT * FROM orders WHERE order_no = '202401010001';

============ 3. 模糊查询 ============
失效案例
SELECT * FROM users WHERE name LIKE '%张%'; 前导模糊
SELECT * FROM users WHERE name LIKE '%张三'; 前导模糊

有效案例
SELECT * FROM users WHERE name LIKE '张%'; 后导模糊,可用索引
SELECT * FROM users WHERE name LIKE '张三%';

优化方案(全文索引)
ALTER TABLE users ADD FULLTEXT INDEX ft_name (name);
SELECT * FROM users WHERE MATCH(name) AGAINST('张三' IN BOOLEAN MODE);

============ 4. OR 条件 ============
失效案例(只有 name 有索引)
SELECT * FROM users WHERE name = '张三' OR age = 25;

优化方案 1UNION
SELECT * FROM users WHERE name = '张三'
UNION
SELECT * FROM users WHERE age = 25;

优化方案 2:确保两个字段都有索引
CREATE INDEX idx_name ON users(name);
CREATE INDEX idx_age ON users(age);

============ 5. 不等于操作符 ============
失效案例
SELECT * FROM users WHERE status != 'active';
SELECT * FROM users WHERE status <> 'active';

优化方案
SELECT * FROM users WHERE status IN ('inactive', 'deleted', 'banned');

============ 6. IS NULL / IS NOT NULL ============
可能失效(取决于 NULL 值比例)
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;

优化方案 1:使用默认值
ALTER TABLE users MODIFY email VARCHAR(255) NOT NULL DEFAULT '';
SELECT * FROM users WHERE email = '';

优化方案 2:使用特殊标记
UPDATE users SET email = 'NULL' WHERE email IS NULL;
SELECT * FROM users WHERE email = 'NULL';

============ 7. 计算操作 ============
失效案例
SELECT * FROM orders WHERE amount + 10 > 100;
SELECT * FROM orders WHERE amount * 1.1 > 100;
SELECT * FROM users WHERE age 5 > 20;

优化方案
SELECT * FROM orders WHERE amount > 90;
SELECT * FROM orders WHERE amount > 100 / 1.1;
SELECT * FROM users WHERE age > 25;

============ 8. 联合索引最左匹配原则 ============
创建联合索引
CREATE INDEX idx_name_age_city ON users(name, age, city);

有效案例
SELECT * FROM users WHERE name = '张三'; 使用索引
SELECT * FROM users WHERE name = '张三' AND age = 25; 使用索引
SELECT * FROM users WHERE name = '张三' AND age = 25 AND city = '北京'; 使用索引
SELECT * FROM users WHERE name = '张三' AND city = '北京'; 部分使用索引

失效案例
SELECT * FROM users WHERE age = 25; 不使用索引
SELECT * FROM users WHERE city = '北京'; 不使用索引
SELECT * FROM users WHERE age = 25 AND city = '北京'; 不使用索引

============ 9. 范围查询后的字段 ============
创建联合索引
CREATE INDEX idx_age_status_city ON users(age, status, city);

部分使用索引
SELECT * FROM users WHERE age > 20 AND status = 'active' AND city = '北京';
说明:age 使用索引,status 和 city 不使用索引(因为 age 是范围查询)

优化方案:调整索引顺序
CREATE INDEX idx_status_city_age ON users(status, city, age);
SELECT * FROM users WHERE status = 'active' AND city = '北京' AND age > 20;

============ 10. SELECT * ============
不推荐(可能导致回表)
SELECT * FROM users WHERE name = '张三';

优化方案:覆盖索引
CREATE INDEX idx_name_email_age ON users(name, email, age);
SELECT name, email, age FROM users WHERE name = '张三'; 不需要回表

============ 11. INNOT IN ============
IN 可以使用索引(数量不要太多)
SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5); 有效

NOT IN 可能失效
SELECT * FROM users WHERE id NOT IN (1, 2, 3); 可能失效

优化方案
SELECT * FROM users WHERE id NOT IN (1, 2, 3) AND id IS NOT NULL;

============ 12. ORDER BYGROUP BY ============
失效案例(排序字段不在索引中)
CREATE INDEX idx_name ON users(name);
SELECT * FROM users WHERE name = '张三' ORDER BY age; age 排序无法使用索引

优化方案
CREATE INDEX idx_name_age ON users(name, age);
SELECT * FROM users WHERE name = '张三' ORDER BY age; 可以使用索引

============ 验证索引使用情况 ============
使用 EXPLAIN 查看执行计划
EXPLAIN SELECT * FROM users WHERE name = '张三';

关键字段说明:
type: ALL(全表扫描)< index < range < ref < eq_ref < const
key: 实际使用的索引
rows: 扫描的行数
Extra: Using index(覆盖索引), Using filesort(文件排序)

============ 索引优化建议 ============
1. 选择性高的列建索引
2. 频繁查询的列建索引
3. 联合索引遵循最左匹配
4. 避免过多索引(影响写入性能)
5. 定期分析和优化索引
ANALYZE TABLE users;
OPTIMIZE TABLE users;

MySQL 索引失效场景速查表

最短总结(8种场景)

场景失效示例优化方案
1. 函数操作 WHERE YEAR(date) = 2024 WHERE date >= '2024-01-01'
2. 类型转换 WHERE phone = 13800138000 WHERE phone = '13800138000'
3. 前导模糊 WHERE name LIKE '%张%' WHERE name LIKE '张%'
4. OR 条件 WHERE a = 1 OR b = 2 改用 UNION 或都加索引
5. 不等于 WHERE status != 'active' WHERE status IN (…)
6. IS NULL WHERE email IS NULL 使用默认值
7. 计算操作 WHERE amount + 10 > 100 WHERE amount > 90
8. 最左匹配 索引(a,b,c) 查询 WHERE b=1 WHERE a=1 AND b=1

快速检查

— 查看执行计划
EXPLAIN SELECT * FROM users WHERE name = '张三';

— 关键指标
— type: ALL(最差)→ index → range → ref → const(最好)
— key: 使用的索引名
— rows: 扫描行数(越少越好)
— Extra: Using index(最好), Using filesort(需优化)

联合索引规则

— 索引:(name, age, city)
WHERE name = '张三' — 使用
WHERE name = '张三' AND age = 25 — 使用
WHERE name = '张三' AND age = 25 AND city = '北京' — 使用
WHERE age = 25 — 不使用
WHERE city = '北京' — 不使用

覆盖索引优化

— 创建覆盖索引
CREATE INDEX idx_name_email ON users(name, email);

— 不需要回表(最快)
SELECT name, email FROM users WHERE name = '张三';

— 需要回表(较慢)
SELECT * FROM users WHERE name = '张三';

常用优化命令

— 查看索引
SHOW INDEX FROM users;

— 分析表
ANALYZE TABLE users;

— 优化表
OPTIMIZE TABLE users;

— 查看慢查询
SHOW VARIABLES LIKE 'slow_query%';

索引设计原则

  • 选择性高:区分度大的列(如 ID、手机号)
  • 频繁查询:WHERE、JOIN、ORDER BY 的列
  • 最左匹配:联合索引按查询频率排序
  • 避免冗余:(a,b) 和 (a,b,c) 只需后者
  • 控制数量:单表索引不超过 5 个
  • 实战案例

    案例 1:日期查询优化

    — 慢查询(索引失效)
    SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01';

    — 优化后(使用索引)
    SELECT * FROM orders
    WHERE created_at >= '2024-01-01'
    AND created_at < '2024-01-02';

    案例 2:分页优化

    — 慢查询(深分页)
    SELECT * FROM users ORDER BY id LIMIT 100000, 20;

    — 优化后(使用索引)
    SELECT * FROM users WHERE id > 100000 ORDER BY id LIMIT 20;

    案例 3:多条件查询

    — 创建合适的联合索引
    CREATE INDEX idx_status_city_age ON users(status, city, age);

    — 高效查询
    SELECT * FROM users
    WHERE status = 'active'
    AND city = '北京'
    AND age > 20;

    监控和诊断

    — 查看索引使用情况
    SELECT * FROM sys.schema_unused_indexes;

    — 查看重复索引
    SELECT * FROM sys.schema_redundant_indexes;

    — 查看表大小
    SELECT
    table_name,
    ROUND(data_length / 1024 / 1024, 2) AS data_mb,
    ROUND(index_length / 1024 / 1024, 2) AS index_mb
    FROM information_schema.tables
    WHERE table_schema = 'your_database';

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » php方案 索引失效场景
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!