T-SQL疑问:CURSOR未遵循TABLESAMPLE规则?
问题分析与解决
你遇到的问题是TABLESAMPLE(5 PERCENT)在游标里没生效,依旧返回全表数据的总和。以下是几个关键细节和解决方向:
1. 先确认TABLESAMPLE本身是否正常
别先盯着游标,先单独测试TABLESAMPLE的行为:
-- 看采样后的行数,正常应该约5000行 SELECT COUNT(*) FROM ints TABLESAMPLE(5 PERCENT); -- 看采样后的总和,肯定不等于5000050000 SELECT SUM(x) FROM ints TABLESAMPLE(5 PERCENT);
如果这两个结果还是全表的数据,说明TABLESAMPLE在你环境里本身没起作用,大概率是统计信息过期导致的,执行以下语句更新统计信息后再试:
UPDATE STATISTICS dbo.ints;
如果单独执行TABLESAMPLE正常,那问题就出在游标上。
2. 游标类型的坑:静态游标可能意外缓存全表
你用的READ_ONLY游标默认是静态游标,SQL Server会把查询结果完整复制到tempdb的临时表中再遍历。理论上它应该复制采样后的结果,但在某些优化场景下,可能会忽略TABLESAMPLE的采样逻辑,直接缓存全表数据。
解决办法很简单,把游标改成快速只进游标(FAST_FORWARD),它不会创建静态副本,直接遍历实时的采样结果:
DECLARE crsr CURSOR FAST_FORWARD FOR select x from ints tablesample (5 percent);
3. 堆表的采样特性要清楚
你的表是堆表(未建聚集索引),TABLESAMPLE是基于数据页随机采样,不是按行数百分比计算。100000行的bigint表大概占99页,5%的采样会选中约5页,对应约5000行。如果想要更贴近行百分比的采样,可以用TOP结合NEWID()实现,比如:
DECLARE crsr CURSOR FAST_FORWARD FOR SELECT TOP 5 PERCENT x FROM ints ORDER BY NEWID();
但要注意,这种方法性能比TABLESAMPLE差,更适合小表场景。
内容的提问来源于stack exchange,提问作者user3779002
相关产品推荐
相关产品推荐

