PHP项目索引优化如何根据查询语句新增调整

wen PHP项目 31

本文目录导读:

PHP项目索引优化如何根据查询语句新增调整

  1. 定位需要优化的查询语句
  2. 使用EXPLAIN分析查询
  3. 根据分析结果新增索引
  4. PHP代码中的索引优化实践
  5. 索引维护与监控
  6. 索引新增检查清单
  7. 索引调整案例
  8. 工具推荐

针对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查询) 

工具推荐

  1. Percona Toolkit - pt-query-digest 分析慢查询日志
  2. MySQL Workbench - 可视化执行计划
  3. Laravel Debugbar - 实时查询监控
  4. phpMyAdmin - 索引管理界面

最终建议:建立索引变更流程,先在测试环境复现慢查询,添加索引后对比执行计划,确认优化后再灰度上线到生产环境,对于关键查询,可建立持续监控,当扫描行数突然增加时触发告警。

抱歉,评论功能暂时关闭!