Sql server 将NEWID()与CTE一起使用以生成行的随机子集会产生奇数结果
我正在一个存储过程中编写一些SQL,以将数据集减少到我想要报告的有限的随机行数 报告以Sql server 将NEWID()与CTE一起使用以生成行的随机子集会产生奇数结果,sql-server,stored-procedures,sql-server-2008-r2,newid,Sql Server,Stored Procedures,Sql Server 2008 R2,Newid,我正在一个存储过程中编写一些SQL,以将数据集减少到我想要报告的有限的随机行数 报告以用户组开始,并应用过滤器指定所需的随机行总数(@SampleLimit) 为了达到预期的结果,我首先创建一个CTE(临时表),包括: top(@SampleLimit)已应用 按用户ID分组(当用户ID多次出现时) order by NEWID()将结果按随机顺序排列 SQL: 一旦我有了这个结果集,我就会删除用户ID不在上一步创建的CTE中的任何结果 delete QueryResults where
用户组开始,并应用过滤器指定所需的随机行总数(@SampleLimit
)
为了达到预期的结果,我首先创建一个CTE(临时表),包括:
top(@SampleLimit)
已应用
按用户ID分组
(当用户ID多次出现时)
order by NEWID()
将结果按随机顺序排列
SQL:
一旦我有了这个结果集,我就会删除用户ID不在上一步创建的CTE中的任何结果
delete QueryResults
where (GroupId = @GroupId) and (UserId not in(select UserId from cte_temp))
我遇到的问题是,有时,我会得到比@SampleLimit
中指定的更多的结果,而其他时候,它的工作方式完全符合预期
我尝试过分解SQL并在应用程序外部执行它,但我无法重现这个问题
我所做的有什么根本性的错误可以解释为什么我偶尔会得到更多我要求的结果吗
完整性-我基于以下答案重新考虑的解决方案:
select top(@SampleLimit) UserId into #T1
from QueryResults
where (GroupId = @GroupId)
group by UserId
order by NEWID()
delete QueryResults
where (GroupId = @GroupId) and (UserId not in(select UserId from #T1))
不确定涉及NEWID()
的SELECT
语句将执行多少次
如果您在QueryResults
和cte_temp
之间获得嵌套循环反半联接,并且计划中没有假脱机,则可能会重复计算QueryResults
中的行数,这意味着对于每个外部行,与不在中进行比较的集合可能完全相同不一样
您可以将结果具体化到一个临时表中,而不是使用CTE来避免这种情况
INSERT INTO #T
SELECT TOP(@SampleLimit) UserId
FROM QueryResults
WHERE ( GroupId = @GroupId )
GROUP BY UserId
ORDER BY NEWID()
然后在删除中引用我建议选择DISTINCT TOP(@SampleLimit).
比GROUP BY
工作得更快。在删除后,您会得到更多的结果吗。。。如果UserID不在(…)
?@Stoleg yes中,则删除会留下比我指定的更多不同的用户。我会根据你的建议测试执行计划above@Stoleg这是正确的,第一个查询将获得我的随机样本集,并且该样本集之外的任何用户都将被删除。这似乎有效。我会做更多的测试,并很快确认,但自从实现上述功能以来,我没有得到错误的计数。感谢您的回答,它解决了这个问题,我将其重新分解为一个删除查询,我已经发布了一个完整性问题。@Tanner-重构为子查询也不能保证有效。确保只对其进行一次评估的唯一方法是自己执行一次并存储结果(例如,在#temp
或@table
变量中),我已按照您的建议再次重构到temp表中&上述解决方案已更新。再次感谢。
INSERT INTO #T
SELECT TOP(@SampleLimit) UserId
FROM QueryResults
WHERE ( GroupId = @GroupId )
GROUP BY UserId
ORDER BY NEWID()