Nested Loops Join性能取决于外表行数、内表索引有效性及统计信息准确性;外表越小、内表连接列有索引、统计信息准确时,I/O和CPU开销最低。
因为Nested Loops的执行开销与外表行数直接相关,而内表每次匹配只需一次索引查找(如果有索引),小结果集意味着外表行数少、总查找次数可控。
Loop Join本质是“对外表每行,查内表一次”。如果外表返回10行,内表有索引,那最多做10次seek;如果外表返回10万行,哪怕每次seek只要2页读,总逻辑读也达20万页。实测中,TempA(7行)作为外表时,TempB(700行)被读100次逻辑页;反过来,TempB作外表则TempA被扫700次——即使页数少,总读取量也飙升。
seek还是scan,取决于连接列是否有有效索引没有索引的内表在Loop Join里等于被迫全表扫描——外表每来一行,内表就扫一遍。这时复杂度从O(N × log M)退化成O(N × M),和数据量平方挂钩。比如外表1000行、内表10万行,无索引时就要做1亿次比较。
Index Seek,而非Table Scan或Clustered Index Scan
WHERE条件若能大幅过滤外表(如WHERE OrderID = 100),比给内表加索引还管用ON a.x = b.x,索引必须以x为前导列才生效SQL Server依赖统计信息估算外表大小。如果UPDATE STATISTICS没跑过,它可能把实际只有5行的外表误估成5000行,从而放弃Loop Join,改选Hash Match——后者内存开销大,且对小结果集反而更重。
DBCC SHOW_STATISTICS('table', 'index')看Rows和Rows Sampled是否接近Estimated Row Count和Actual Row Count,差10倍以上就该更新统计AUTO_UPDATE_STATISTICS_ASYNC OFF避免延迟真正卡住Loop Join性能的,往往不是算法本身,而是外表行数不可控 + 内表缺索引 + 统计信息过期这三者叠加。单独解决任一环节,都可能让查询从秒级降到毫秒级。