mysql优化器在in列表≥200时放弃精确统计导致执行计划错误;sql超长触发packet过大错误;uuid比int大幅增加sql体积;临时表join需建索引、批量插入、analyze及防null;分批查询须动态计算批次大小。

IN参数一多,MySQL就“算不准”了
不是慢,是优化器直接放弃精确估算——eq_range_index_dive_limit默认值为200,一旦IN列表长度≥200,MySQL就不再扫描索引树去统计真实行数,转而用粗略的统计值估算成本。结果常选错执行计划:该走range却变成ALL,索引形同虚设。
你看到EXPLAIN里type: ALL、rows高得离谱,八成就是这个原因。别怪索引没建好,是优化器根本没认真看它。
SQL字符串超长,连解析都失败
max_allowed_packet(默认4MB)和net_buffer_length(默认16KB)共同卡住入口:拼出来的完整SQL字符串一旦超过max_allowed_packet * 0.7(建议留缓冲),就会报Packet for query is too large,连接直接断开,连执行计划都看不到。
- INT型ID每条占约4–12字节,UUID则轻松占36字节——同样1万个值,后者SQL体积可能翻3倍
- 客户端驱动(如MySQL Connector/J)对超长参数列表处理不一致,有的静默截断,有的抛
CommunicationsException
临时表JOIN不是建完就完事
建TEMPORARY TABLE只是第一步,没配对关键动作,性能反而更差:
- 没显式定义
PRIMARY KEY或INDEX:JOIN时无索引可走,比IN还慢 - 用单条
INSERT逐行写入:1万条ID要发1万次网络往返,连接池和CPU全被拖垮 - 忘了
ANALYZE TABLE tmp_ids:尤其InnoDB引擎下,优化器不知道临时表数据分布,JOIN仍可能选错驱动表 - 临时表里混入
NULL:ON t.id = i.id在任一侧为NULL时恒为FALSE,查不到任何结果但不报错
分批查询最容易漏掉的三件事
看似简单,实操中90%的线上问题出在这几个细节:
- 批次大小硬写死
1000:实际应按平均ID长度动态计算,目标是单条SQL总长 max_allowed_packet * 0.7 - 结果合并靠应用层
Set去重:数据库返回顺序不确定,不同批次间可能重复或漏行 - 没控制并发粒度:10个批次并发发出去,若连接池只有8个空闲连接,会排队阻塞甚至超时
真正卡住的从来不是语法上限,而是解析阶段的内存分配、优化器的成本误判、以及临时表或分批逻辑里那些不起眼却致命的配置缺失。











