TABLESAMPLE返回错误的行数?

时间:2012-05-23 18:34:20

标签: sql-server tsql sql-server-2005

我刚刚发现了TABLESAMPLE子句,但令人惊讶的是它没有返回我指定的行数。

我使用的表有~14M行,我想要一个10000行的任意样本。

select * from tabData TABLESAMPLE(10000 ROWS)

每次我执行它(8000到14000之间)时,我得到的不是10000而是一个不同的数字。

这里发生了什么,我是否误解了TABLESAMPLE的预期目的?

修改

David's link解释得非常好。

这将以有效的方式返回10000个大致随机的行:

select TOP 10000 * from tabData TABLESAMPLE(20000 ROWS);

并且REPEATABLE选项有助于始终保持相同(除非数据已更改)

select TOP 10000 * from tabData TABLESAMPLE(10000 ROWS) REPEATABLE(100);

因为我想知道使用TABLESAMPLE和大量行来确保(?)得到正确的行号是否更加昂贵,我已经测量过了;

1.loop(20次):

select TOP 10000 * from tabData TABLESAMPLE(10000 ROWS);

(9938 row(s) affected)
(10000 row(s) affected)
(9383 row(s) affected)
(9526 row(s) affected)
(10000 row(s) affected)
(9545 row(s) affected)
(9560 row(s) affected)
(9673 row(s) affected)
(9608 row(s) affected)
(9476 row(s) affected)
(9766 row(s) affected)
(10000 row(s) affected)
(9500 row(s) affected)
(9941 row(s) affected)
(9769 row(s) affected)
(9547 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(9478 row(s) affected)
First batch(only 10000 rows) completed in: 14 seconds!

2.loop(20次):

select TOP 10000 * from tabData TABLESAMPLE(10000000 ROWS);

(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
(10000 row(s) affected)
Second batch(max rows) completed in: 13 seconds!

3.loop:使用ORDER BY NEWID():

对100%随机行进行计数器检查
select TOP 10000 * from tabData ORDER BY NEWID();

(10000 row(s) affected)

在持续 23分钟

的一次执行后取消

结论

令人惊讶的是,使用精确TOP子句和TABLESAMPLE中的大数字的方法更慢。因此,它是ORDER BY NEWID()的一个非常有效的替代方案,如果行不是每行随机而是每页级别无关紧要(表的每个8K页面都有一个随机值)。

4 个答案:

答案 0 :(得分:4)

请参阅article here。您需要添加一个top子句和/或使用repeatable选项来获取所需的行数。

答案 1 :(得分:3)

来自文档。

  

返回的实际行数可能会有很大差异。如果   如果指定了一个较小的数字,例如5,则可能无法收到结果   在样本中。

http://msdn.microsoft.com/en-us/library/ms189108(v=sql.90).aspx

答案 2 :(得分:1)

此行为已在之前记录过。它上面写了一篇很好的文章here

我相信你可以通过每次都使用相同的种子传递REPEATABLE来解决它。以下是来自写作的信息:

  

......你会注意到不同的   每次返回行数。没有任何数据变化,   重新运行相同的查询会不断给出不同的结果。这是   TABLESAMEPLE子句的非确定性因子。如果表是静态的   并且行不会被更改,这可能是返回不同的原因   每次执行时返回的行数。因素是10   PERCENT不是表行或表记录的百分比,它   表格数据页面的百分比。一旦样本页面   选择的数据,返回所选页面中的所有行,它   不会限制从该页面采样的行数。填充因子   所有页面的数量取决于表的数据。这使得   脚本每次返回结果集中的不同行数   执行。 REPEATABLE选项会导致选定的样本   又回来了。使用相同的repeat_seed指定REPEATABLE时   值,SQL Server返回相同的行子集,只要没有   已经对表格进行了更改。指定REPEATABLE时   一个不同的repeat_seed值,SQL Server通常会返回一个   表中行的不同样本。

答案 3 :(得分:1)

我也观察到了同样的情况。

页面说明绝对有意义并敲响了一个响铃 - 当行大小固定时,您应该会看到更多可预测的行数。在没有可空列或可变长度列的表上尝试。

事实上,我只是用它来证明一个关于使用它进行更新的理论(你可能受到我同样的问题的刺激),选择TABLESAMPLE(50000 ROWS)实际上影响了49,849行。

相关问题