MSSQL无索引场景:单表加载与两表Union加载的效率对比
单表 vs 两表Union加载效率(MSSQL无索引场景)
嘿,这个问题我之前做报表系统性能优化的时候专门测试过,结合MSSQL的执行逻辑给你唠明白:
核心结论(无索引基础场景)
在没有任何索引的情况下,单表加载的效率几乎肯定比两表Union的方式更高,原因全在MSSQL的执行流程差异上:
单表加载的执行逻辑
当你从单表读取数据时,MSSQL只需要做一次全表扫描(Table Scan),直接遍历表的所有数据页,把符合条件的数据(如果有过滤条件的话)一次性返回。整个过程没有额外的合并、排序开销,是最直接的读取路径。
两表Union的执行逻辑
这里得先明确:UNION和UNION ALL是完全不同的——你问题里提到的Union会自动去重,所以MSSQL的执行步骤是:
- 分别对两个表做全表扫描,生成两个独立的结果集
- 把两个结果集写入临时存储(比如tempdb)
- 对合并后的结果集做排序,去除重复数据
- 最终返回去重后的结果
这一套流程下来,不仅多了一次全表扫描,还额外增加了临时存储写入和排序去重的开销,这些都是单表加载不会有的额外消耗。哪怕换成不需要去重的UNION ALL,依然需要两次扫描+结果合并,还是不如单表一次扫描高效。
特殊场景的例外情况
当然也有极端特殊的情况,比如其中一个表是空表——这时候Union的开销和单表差不多,但这种场景几乎没有实际业务意义。如果两个表的数据量都极小,差异可能不明显,但数据量一旦上来,单表的优势就会立刻凸显。
优化建议
- 如果业务上没有强制拆分的需求(比如不需要按业务隔离、历史数据归档等),直接把同类数据存在单表里,这是最优选择,加载效率最高。
- 如果必须拆分数据(比如历史数据和当前业务数据分开存储),优先用
UNION ALL替代UNION(如果你的业务允许重复数据,或者能保证两个表没有重复数据),这样可以省去排序去重的巨大开销。 - 无论单表还是分表,都建议根据你的加载查询条件添加合适的索引——比如如果每次加载都按某个字段过滤,给这个字段加非聚集索引,能大幅减少扫描的数据量,比纠结单表还是分表的提升更明显。
举个简单的执行计划对比例子:
单表查询:
SELECT * FROM Product WHERE Type = 'Electronics'执行计划是一次
Table Scan,开销占比100%。两表Union查询:
SELECT * FROM ProductOld WHERE Type = 'Electronics' UNION SELECT * FROM ProductNew WHERE Type = 'Electronics'执行计划会是两个
Table Scan(各占约30%),加上一个Sort操作(占约40%),总开销远高于单表。
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

