SQL Server 2014中带Except子句的Count查询为何与结果查询耗时相同?
为什么COUNT(*)查询和结果集查询耗时一模一样?
兄弟,咱们先拆解下你这条SQL的执行逻辑,就能明白为啥俩查询耗时没差了——你的COUNT(*)根本没走捷径,它得先把内层所有复杂逻辑跑完,生成完整的结果集,最后才数个数。这和直接把结果查出来的工作量完全相同,耗时当然就一样了。
具体来说,你的查询里有几个拖慢速度的“元凶”,同时也是导致COUNT(*)没法偷懒的原因:
- 重复的去重操作:你在两个子查询里同时用了
DISTINCT和GROUP BY title, version,这纯纯是做无用功——GROUP BY本身就会帮你按title和version分组去重,再加DISTINCT只会让数据库多跑一遍冗余的去重流程,白耗资源。 - 相关子查询的嵌套开销:两个
EXISTS/NOT EXISTS都是相关子查询,意思是外层book表的每一条记录,都要去user表查一遍匹配的数据。如果两张表数据量大,这会触发大量的嵌套循环,性能直接拉胯。 - EXCEPT的执行机制:EXCEPT的逻辑是先把左右两个子查询的结果集全生成出来,再做差集比对。不管你是要结果还是要计数,这一步都必须把两个结果集都算完才能进行,完全没法跳过。
那怎么优化呢?给你几个实操建议:
- 砍掉多余的DISTINCT:把两个子查询里的
DISTINCT直接删掉,只保留GROUP BY title, version,效果完全一样,但能省掉一遍去重的开销。 - 合并查询逻辑,去掉EXCEPT:仔细看你的逻辑,其实是要找“title不为空,且不存在user表中column1匹配book.column1的记录,同时又不在‘存在user表column2匹配book.column1’的book记录里”的title+version组合。咱们可以把这逻辑合并成一个查询,不用分开两个子查询再做EXCEPT:
SELECT COUNT(*) AS id FROM ( SELECT title, version FROM book AS b WHERE b.title IS NOT NULL -- 满足左半部分的NOT EXISTS条件 AND NOT EXISTS (SELECT * FROM [user] AS u WHERE u.column1 = b.column1) -- 同时不满足右半部分的EXISTS条件(也就是不在右半集合里) AND NOT EXISTS (SELECT * FROM [user] AS u WHERE u.column2 = b.column1) GROUP BY title, version ) c
这样就避免了EXCEPT需要生成两个独立结果集的额外开销。
3. 加合适的索引:给book表建column1 + title + version的复合索引,让数据库能快速筛选和分组:
CREATE INDEX IX_book_column1_title_version ON book(column1, title, version);
再给user表的column1和column2分别建单独的索引,加速子查询的匹配:
CREATE INDEX IX_user_column1 ON [user](column1); CREATE INDEX IX_user_column2 ON [user](column2);
- 看执行计划找瓶颈:在SSMS里按Ctrl+M打开实际执行计划,跑一遍你的查询,看看是不是有全表扫描、嵌套循环这类高开销的操作,针对性优化。
总结一下:你的COUNT(*)查询本质上是“先生成完整结果集,再数个数”,和直接查结果集的工作量完全一致,所以耗时相同。优化的核心就是简化逻辑、减少冗余操作,再配合索引提升效率。
内容的提问来源于stack exchange,提问作者Kivo
相关产品推荐
相关产品推荐

