SQL关联查询中驱动表选择基于过滤后的预估行数,而非物理行数。统计信息过期、被驱动表无索引或索引失效均会严重拖慢性能。LEFTJOIN固定左表为驱动表。可通过子查询或STRAIGHT_JOIN强制指定驱动表,并核实EXPLAIN的rows与key字段。
驱动表选错,查询就可能从毫秒级变成分钟级——这事儿不是SQL写错了,而是优化器被统计信息误导了。先说一个核心判断:优化器决定驱动表的依据,是「过滤后的预估行数」,而不是建表时的物理行数。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
举个例子,orders表有200万行,但加上WHERE order_status IN (1,2)后只剩50万;而users表虽然只有10万行,却没有任何过滤条件。这时候,orders反而更可能被选为驱动表——因为优化器只认经过过滤后的预估行数。
EXPLAIN看rows列,它反映的是该表在JOIN前的预估扫描行数,不是总行数ANALYZE TABLE)会让rows严重失真,优化器自然就误判了LEFT JOIN:左表固定为驱动表,哪怕它经过WHERE后仍然很大,优化器也无权调换顺序嵌套循环连接(Nested Loop Join)这个算法,之所以能反赌,全靠被驱动表有索引可以快速定位匹配行。一旦这个前提不成立,小表驱动大表就退化成暴力扫描——性能自然雪崩。
EXPLAIN输出中的key字段:如果为NULL,说明ON字段没走索引ON DATE(l.create_time) = '2026-04-23'、ON CAST(o.user_id AS CHAR) = u.id——函数或类型转换直接让索引失效BIGINT对INT、VARCHAR(20)对VARCHAR(50)都可能触发隐式转换,索引同样会失效别等优化器猜,尤其在多表JOIN或复杂WHERE条件下,主动控制比依赖更可靠。
SELECT * FROM (SELECT user_id FROM orders WHERE order_status IN (1,2)) t JOIN users u ON t.user_id = u.id,让优化器一眼看清驱动侧只有几万行INNER JOIN场景下加STRAIGHT_JOIN:如SELECT STRAIGHT_JOIN ... FROM small_table s JOIN large_table l ON s.id = l.small_idLEFT JOIN,如果左表实际很大,就要考虑是否真的需要LEFT——有时改写成INNER JOIN加UNION ALL补NULL,反而更高效说到底,最容易被忽略的两个动作:确认EXPLAIN里的rows是否真实,以及盯住被驱动表的key是否非空。其他所有技巧,都建立在这两个事实成立的基础上。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述