悠悠楠杉
网站页面
在PHP开发中,数据库查询性能往往是系统瓶颈的“重灾区”。尤其当数据量突破百万级时,一个未优化的SQL查询可能拖垮整个应用。如何让MySQL乖乖听话?索引和查询优化器是关键。本文将用实战案例拆解这两大核心,教你写出飞一般的查询代码。
MySQL的查询优化器并不总是明智的。有时它会忽略最佳索引,选择全表扫描。这时需要通过索引提示(Index Hints)手动干预。
场景示例:用户表users有age和city的联合索引,但优化器误用了单字段索引:sql
SELECT * FROM users WHERE age > 25 AND city = '北京';
通过FORCE INDEX强制使用联合索引:
SELECT * FROM users FORCE INDEX(age_city_idx) WHERE age > 25 AND city = '北京';
注意事项:
1. 过度使用FORCE INDEX可能导致后续数据分布变化时性能下降;
2. 优先用USE INDEX(建议而非强制)或IGNORE INDEX(排除低效索引)。
优化器的决策依赖统计信息,但我们可以通过以下方式引导:
OR导致索引失效,改用UNION:
-- 低效写法
SELECT * FROM products WHERE category = '电子产品' OR price > 5000;
-- 优化写法
SELECT * FROM products WHERE category = '电子产品'
UNION
SELECT * FROM products WHERE price > 5000;
LIMIT会促使优化器优先使用排序索引:sql
SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 10;结合PHP代码时,需注意预处理语句与索引的配合:
// PDO预处理中使用索引提示
$stmt = $pdo->prepare("
SELECT /*+ INDEX(users age_city_idx) */ id, name
FROM users
WHERE age > :age AND status = 1
");
$stmt->execute([':age' => 25]);
监测工具:
- 使用EXPLAIN分析执行计划:sql
EXPLAIN SELECT * FROM users WHERE age > 25;
- 通过PHP的SHOW PROFILE定位耗时步骤:
$pdo->query("SET profiling = 1");
$pdo->query("SELECT * FROM large_table");
$result = $pdo->query("SHOW PROFILE FOR QUERY 1")->fetchAll();
WHERE phone = 13800138000(字符串转数字)会导致索引失效;ANALYZE TABLE更新统计信息,避免优化器误判。通过合理使用索引提示和优化器引导,配合PHP的预处理机制,即使是千万级数据的查询也能控制在毫秒级响应。记住:优化是持续过程,需结合监控数据不断调整。