【问题标题】:Get random number of rows from SQL Server table从 SQL Server 表中获取随机行数
【发布时间】:2017-05-08 14:18:44
【问题描述】:

我正在尝试使用快速方法从一个大表(超过 100 万行)中获取 5 个随机行数。

到目前为止,我使用这些 SQL 查询进行了测试:

方法一

Select top 5 customer_id, customer_name 
from Customer TABLESAMPLE(1000 rows) 
order by newid()

此方法估计 I/O 成本为 0.0127546,因此速度非常快(索引扫描非集群)

方法二

select top 5 customer_id, customer_name 
from Customer 
order by newid()

此方法的排序估计 I/O 成本为117.21189,索引扫描非集群估计 I/O 成本为2.8735,所以这会影响性能

方法3

select top 5 customer_id, customer_name 
from Customer 
order by rand(checksum(*))

此方法的排序估计 I/O 成本为 117.212,索引扫描非聚集估计 I/O 成本为 213.149,此查询比所有查询都慢,因为估计子树成本为 213.228,因此非常慢。

更新:

方法四

select top 5 customer_id, customer_name, product_id
from Customer 
Join Product on product_id = product_id
where (customer_active = 'TRUE')
order by checksum(newid())

这种方法更好,速度也很快。所有的基准测试都很好。

问题

如何将方法 4 转换为 LINQ-to-SQL?谢谢

【问题讨论】:

  • 您是在询问提高随机查询性能还是将查询转换为 LINQ?
  • 您希望结果有多随机? TABLESAMPLE 并不是真正随机的(除非您的行太大以至于只有一个适合页面)。
  • @JuanCarlosOropeza 是的,首先,如果不可能,我希望将方法 1 转换为 LINQ,然后我正在寻找更好的方法。
  • @GordonLinoff:实际上客户只是想填满空间,所以我只需要显示 5 个随机行而不影响性能。
  • 如果你想填满空间,为什么不只显示前 5 名?

标签: sql-server entity-framework linq random guid


【解决方案1】:

如果您想将 方法 2 转换为 Linq To 实体,只需使用jitender 回答的解决方案,如下所示:

var randomCoustmers = context.Customers.OrderBy(x => Guid.NewGuid()).Take(5);

但是对于在基准测试之后非常快的方法 1,您需要执行以下 C# 代码,因为 Linq To Entities 没有此 SQL 语句 TABLESAMPLE(1000 rows) 的 LINQ 等效项。

var randomCoustmers = context.Customers.SqlQuery("Select TOP 5 customer_id, customer_name from Customer TABLESAMPLE(1000 rows) order by newid()").ToList();

您可以将 SQL 语句移动到 SQL 视图或存储过程中,该过程将接收要接受的客户数量。

更新

对于似乎非常快的 方法 4(始终遵循您的基准),您可以执行以下 Linq To Entities:

var randomCoustmers = context.Customers.OrderBy(c => SqlFunctions.Checksum(Guid.NewGuid()).Take(5);

Entity Framework 可以将所有定义在SqlFunctions 类中的函数翻译成SQL。在这些函数中,我们有 Checksum 函数,它可以满足您的需求。

如果您想加入其他表,您可以使用 Linq To Entites 轻松完成,所以我只是通过仅查询 Customers DbSets 来简化我的版本。

【讨论】:

  • 我要测试它,同时我已经更新了问题,请你检查一下。谢谢
  • 非常感谢。 SqlFunctions 的方法 4 像魅力一样工作。非常流畅,服务器没有负载。再次感谢:)
【解决方案2】:

如上所述 Here是最好的办法:

var randomCoustmers = Customers.OrderBy(x => Guid.NewGuid()).Take(5);

【讨论】:

  • 在这种情况下最好使用duplicated question关闭选项
  • 您转换 Method 2 而不是 Method 1 正如 OP 所期望的那样。
  • 其实我已经在用了,但是I/O成本很高,影响了性能。 方法2同理。我正在寻找更好的方法。
  • @JuanCarlosOropeza 我也有同样的想法,但我无权将其标记为重复 :-)
  • 那么我建议你创建一个新问题并问这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 2014-10-04
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 2023-03-11
  • 2011-02-20
相关资源
最近更新 更多