对战网站MySQL匹配查询耗时过长:符合条件数据量少仍性能异常
咱们来拆解下这个匹配查询慢的问题——你提到系统里只有15000条user_match数据(仅40条满足stack=0.5且status='search')、15000支队伍,但elo为150的队伍发起匹配时查询却极慢,大概率是索引缺失或者查询逻辑不够高效导致的,给你几个具体的优化方向:
优先给核心过滤字段建复合索引
你的匹配场景核心过滤条件是status='search'和stack=0.5,还要关联队伍的elo属性做匹配。首先给user_match表创建复合索引,让数据库能快速定位到符合条件的匹配记录:CREATE INDEX idx_match_search_stack ON user_match(status, stack);如果查询需要关联队伍表的
elo字段,那队伍表的elo字段也得单独建索引;如果业务允许,甚至可以把elo冗余到user_match表中,避免跨表关联的额外开销。用
EXPLAIN排查查询执行计划
先确认你的查询是不是触发了全表扫描。执行EXPLAIN命令分析你的匹配查询:EXPLAIN SELECT [你的查询语句];看结果里的
type列,如果是ALL就说明是全表扫描,那要么是索引没生效(比如用了函数操作字段、模糊匹配以%开头),要么是索引建错了方向。另外,尽量避免SELECT *拉取所有字段,只查询需要的列也能减少数据传输开销。调整查询逻辑的执行顺序
既然符合status='search'且stack=0.5的user_match只有40条,那应该先筛选出这40条记录,再关联队伍表匹配elo,而不是先关联两张表再过滤。比如先执行:SELECT id FROM user_match WHERE status='search' AND stack=0.5;拿到这些id后,再去关联队伍表查找elo接近150的队伍,这样能大幅减少关联的数据量。
排查锁与事务阻塞问题
有时候数据量不大但查询慢,可能是查询碰到了写操作的锁等待。可以用SHOW PROCESSLIST命令查看当前数据库的进程状态,看看有没有处于Locked状态的进程,排查是不是有未提交的事务在占用资源。业务层面优化匹配范围
既然是elo匹配,没必要全量查找所有符合条件的队伍,可以先缩小elo的匹配范围,比如只查找elo在150±20范围内的队伍,这样过滤后的结果集更小,查询速度自然更快。另外,定期清理过期的search状态匹配(比如超过10分钟没匹配成功的改为expired),也能减少需要扫描的数据量。
内容的提问来源于stack exchange,提问作者Quentin Lerebours

