本文目录导读:

针对PHP项目的索引优化,通常需要结合慢查询日志、执行计划和业务查询模式来新增或调整索引,以下是分步骤的最佳实践:
定位需要优化的查询语句
开启MySQL慢查询日志
-- 查看是否开启 SHOW VARIABLES LIKE 'slow_query_log%'; -- 临时开启(生产环境谨慎使用) SET GLOBAL slow_query_log = 1; SET GLOBAL long_query_time = 2; -- 超过2秒记录 SET GLOBAL log_queries_not_using_indexes = 1;
在PHP代码中临时开启慢查询记录
// 在需要调试的代码段前
$pdo->exec("SET SESSION long_query_time = 1");
$pdo->exec("SET SESSION slow_query_log = 1");
// 执行你的查询
// 查看日志文件
使用EXPLAIN分析查询
EXPLAIN SELECT * FROM users WHERE status = 'active' AND created_at > '2024-01-01' ORDER BY last_login DESC;
重点关注字段:
type: 全表扫描(ALL) → 需要索引key: 当前使用的索引rows: 扫描行数Extra: 文件排序(Using filesort) → 需要排序索引
根据分析结果新增索引
WHERE条件查询
-- 原始慢查询 SELECT * FROM orders WHERE user_id = 123 AND status = 'completed'; -- 需要组合索引(注意字段顺序) ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
口诀:区分度高的放前面,等值查询放前面
排序查询
-- 产生文件排序 SELECT * FROM articles WHERE category_id = 5 ORDER BY created_at DESC; -- 索引优化(包含排序字段) ALTER TABLE articles ADD INDEX idx_category_created (category_id, created_at DESC);
模糊查询
-- 前缀模糊查询可用索引 SELECT * FROM products WHERE sku LIKE 'ABC%'; -- 后缀模糊不能用索引(考虑全文索引) SELECT * FROM products WHERE sku LIKE '%XYZ'; -- 优化方案:存储逆转后的字段 ALTER TABLE products ADD reversed_sku VARCHAR(255);
JOIN查询
-- 在两个表JOIN字段上添加索引 ALTER TABLE orders ADD INDEX idx_user_id (user_id); ALTER TABLE users ADD INDEX idx_id (id);
PHP代码中的索引优化实践
使用ORM框架的查询优化
// Laravel Eloquent - 添加索引建议
Schema::table('users', function (Blueprint $table) {
$table->index(['status', 'created_at']);
$table->index('email');
});
// 或通过迁移新增索引
php artisan make:migration add_index_to_users_table
// 在迁移文件中
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->index(['department_id', 'role']);
});
}
动态索引选择(备选方案)
// 根据查询条件动态选择最优索引
class QueryOptimizer {
public function buildIndexHint($conditions) {
if (isset($conditions['user_id']) && isset($conditions['status'])) {
return "USE INDEX (idx_user_status)";
}
return "";
}
}
$sql = "SELECT * FROM orders {$optimizer->buildIndexHint($where)} WHERE ...";
索引维护与监控
查看当前索引使用情况
-- 查看索引使用频率 SELECT * FROM sys.schema_index_statistics WHERE table_schema = 'your_database'; -- 查看未使用的索引 SELECT * FROM sys.schema_unused_indexes;
使用PHP脚本监控慢查询
// monitoring.php
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
// 获取慢查询日志
$stmt = $db->query("SHOW GLOBAL STATUS LIKE 'Slow_queries'");
$row = $stmt->fetch();
echo "当前慢查询数: " . $row['Value'] . "\n";
// 获取最近慢查询
$stmt = $db->query("SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10");
while ($log = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $log['sql_text'] . "\n";
}
索引新增检查清单
✅ 确认索引必要性:检查查询是否确实需要
✅ 选择合适的索引类型:B-Tree (普通)、复合、全文、空间
✅ 控制索引数量:单表不超过5-6个索引
✅ 考虑维护成本:写频繁的表要谨慎
✅ 测试新索引效果:通过执行计划对比
✅ 监控写入性能:索引新增后观察写操作延迟
✅ 文档化:记录为什么添加这个索引
索引调整案例
案例:文章列表页优化
// 原始查询(慢)
$articles = Article::where('status', 'published')
->whereIn('category_id', [1,2,3])
->orderBy('publish_time', 'desc')
->paginate(20);
// 执行计划显示:
// - 使用了status索引,但category和排序需要额外处理
// - 产生Using filesort
// 优化方案
ALTER TABLE articles ADD INDEX idx_category_status_time
(status, category_id, publish_time DESC);
// 或使用覆盖索引(如果只查少数字段)
ALTER TABLE articles ADD INDEX idx_cover_query
(status, category_id, publish_time DESC, title, summary);
验证优化效果
EXPLAIN SELECT * FROM articles WHERE status = 'published' AND category_id IN (1,2,3) ORDER BY publish_time DESC; -- 优化后应该显示: -- type: range -- key: idx_category_status_time -- Extra: Using index condition; Using filesort (如果IN查询)
工具推荐
- Percona Toolkit -
pt-query-digest分析慢查询日志 - MySQL Workbench - 可视化执行计划
- Laravel Debugbar - 实时查询监控
- phpMyAdmin - 索引管理界面
最终建议:建立索引变更流程,先在测试环境复现慢查询,添加索引后对比执行计划,确认优化后再灰度上线到生产环境,对于关键查询,可建立持续监控,当扫描行数突然增加时触发告警。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播