【问题标题】:100k Rows Returned in a random order, without a SQL time out please100k 行以随机顺序返回,请没有 SQL 超时
【发布时间】:2010-02-23 23:53:02
【问题描述】:

好的,

去年我一直在阅读大量关于返回随机行集的内容,我们提出的解决方案是

ORDER BY newid()

这适用于 10-20k 行时,我们会遇到 SQL 超时,执行计划告诉我 76% 的查询成本来自这条线。当我们有大量行时,删除这条线会使速度提高一个数量级。

我们的用户需要像这样一次处理多达 100k 行。

为大家提供更多细节。

我们有一个包含 260 万个 4 位字母数字代码的表格。我们使用其中的一组随机来进入场地。例如,如果我们有一个容量为 5000 的活动,将从表中随机抽取 5000 个,然后作为条形码发给每个客户,然后门口的条形码扫描应用程序有相同的 5000 列表。使用 4 位字母数字代码(而不是像 GUID 那样愚蠢的长数字)的原因是人们很容易写下数字(或通过短信发送给朋友)并带上数字并手动输入,所以我们不想要大量的字符。顺便说一句,客户喜欢最后一点。

有没有比ORDER BY newid() 更好的方法,或者有更快的方法从 260 万的表中获取 100k 随机行?

哦,我们使用的是 MS SQL 2005。

谢谢,

【问题讨论】:

标签: sql-server sql-server-2005 random


【解决方案1】:

有一篇名为“Selecting Rows Randomly from a Large Table”的 MSDN 文章讨论了这个确切的问题并给出了解决方案(不使用排序,而是在生成的列上使用 WHERE 子句来过滤行)。

查询速度慢的原因是ORDER BY 子句导致将整个表复制到 tempdb 中进行排序。

【讨论】:

    【解决方案2】:

    如果您想生成随机的 4 位数代码,为什么不直接生成它们而不是尝试将它们从数据库中提取出来?

    生成从 0 到 1,679,616 的 100k 个唯一数字(这是唯一的四位字母数字代码的数量,忽略大小写 - 260 万行必须有一些重复)并将它们转换为您的四位代码。

    【讨论】:

      【解决方案3】:

      您不必排序。

       DECLARE @RandomNumber int
       DECLARE @Threshold float
       SELECT @RandomNumber = COUNT(*) FROM customers
       SELECT @Threshold = 50000 / @RandomNumber
      
       SELECT TOP 50000 * FROM customers WHERE rand() > @Threshold ORDER BY newid()
      

      【讨论】:

      • 您仍在排序,因为您的查询中有ORDER BY newid()
      • 但我只排序 ca 50k,而不是整个表。问题是,如果我们使用 rand() 选择超过 50k,我们必须删除它们。但是,如果我们只拿 TOP 而不进行排序,那么名单上的第一个人将获得特权。
      【解决方案4】:

      顺便说一句,如果你替换它的性能如何

      ORDER BY newid()
      

      通过

      ORDER BY CHECKSUM(newid())
      

      【讨论】:

        【解决方案5】:

        一种想法是将过程分解为步骤。在表中为 GUID 添加一列,然后在表中添加 GUID 执行更新语句。如有必要,这可以提前完成。然后,您应该能够在 GUID 列上使用 orderby 运行查询,以同样的方式接收结果。

        【讨论】:

          【解决方案6】:

          您是否尝试过在给定的 int 列上使用 %(模)?不确定你的表结构是什么,但你可以这样做:

          选择前 50000 个 * 从你的表 其中 CAST((CAST(ASCII(SUBSTRING(venuecode,1,1)) as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,2,1))as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,3,1))as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,4,1))as varchar(3))) as bigint) % 500000 介于 0 和 50000 之间

          上面的代码将获取您所有的字母数字场地并将它们转换为整数,然后将整个表格分成 500,000 个存储桶,您将获取位于 0 到 50000 之间的前 50000 个存储桶。您可以使用数字在 % since (500,000) 之后,你可以在两者之间玩。这应该为您随机化。不确定 where 子句是否会影响性能,但值得一试。此外,如果没有 order by,则无法保证顺序(如果您有多个 cpu 和线程)。

          【讨论】:

            猜你喜欢
            • 2010-11-10
            • 2019-02-01
            • 2017-12-07
            • 1970-01-01
            • 2011-03-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-20
            相关资源
            最近更新 更多