已建索引SQL查询仍全表扫描的优化求助
问题分析与优化方案
你的核心问题是OR条件+多列!=判断导致索引无法有效过滤数据,即便命中索引,也需要扫描接近全表的行数。以下是针对性的优化方案:
1. 重构索引,打造高效覆盖索引
当前的idx_player_status索引大概率无法适配你的查询逻辑,建议创建两个针对性的覆盖索引:
-- 适配to_player_id的查询场景 CREATE INDEX idx_to_player_del_status ON p_rpts(to_player_id, delete_status); -- 适配from_player_id的查询场景 CREATE INDEX idx_from_player_del_status ON p_rpts(from_player_id, delete_status);
注:MySQL InnoDB引擎中,主键会自动包含在二级索引中,无需额外添加;其他数据库(如PostgreSQL)可使用
INCLUDE (id)创建覆盖索引,避免回表查询。
2. 优化UNION查询,兼顾性能与准确性
原UNION查询的性能瓶颈在于自动去重的排序开销,改用UNION ALL+外层去重的方式,既能利用索引快速过滤,又能保证计数准确:
SELECT COUNT(DISTINCT id) FROM ( -- 匹配to_player_id且状态符合条件的记录 SELECT id FROM p_rpts WHERE to_player_id = '191717' AND delete_status NOT IN (1, 3) UNION ALL -- 匹配from_player_id且状态符合条件的记录 SELECT id FROM p_rpts WHERE from_player_id = '191717' AND delete_status NOT IN (2, 3) ) AS combined_data;
UNION ALL不会对结果去重,执行速度远快于UNION;- 外层用
COUNT(DISTINCT id)确保不会重复计数同一行数据。
3. 辅助优化手段
- 更新表统计信息:若数据库统计信息过时,优化器可能误判索引效率,执行
ANALYZE TABLE p_rpts;(MySQL)或对应数据库的统计更新命令; - 避免低效条件:尽量用
NOT IN替代多个!=,逻辑更清晰且优化器更容易处理; - 验证执行计划:执行
EXPLAIN查看子查询的type列,若显示ref或range,说明索引已生效;rows列应大幅小于全表行数。
内容的提问来源于stack exchange,提问作者Zeyd Lprn
相关产品推荐
相关产品推荐

