当前位置:  开发笔记 > 编程语言 > 正文

从Linq到Sql的随机行

如何解决《从Linq到Sql的随机行》经验,为你挑选了5个好方法。

当我有条件时,使用Linq to SQL检索随机行的最佳(和最快)方法是什么,例如某些字段必须为true?



1> Marc Gravell..:

您可以使用假UDF在数据库中执行此操作; 在部分类中,向数据上下文添加方法:

partial class MyDataContext {
     [Function(Name="NEWID", IsComposable=true)] 
     public Guid Random() 
     { // to prove not used by our C# code... 
         throw new NotImplementedException(); 
     }
}

然后就是order by ctx.Random(); 这将在SQL-Server提供随机排序NEWID().即

var cust = (from row in ctx.Customers
           where row.IsActive // your filter
           orderby ctx.Random()
           select row).FirstOrDefault();

请注意,这仅适用于中小型表; 对于大型表,它会对服务器产生性能影响,找到行数(Count),然后随机选择一个()会更有效Skip/First.


计数方法:

var qry = from row in ctx.Customers
          where row.IsActive
          select row;

int count = qry.Count(); // 1st round-trip
int index = new Random().Next(count);

Customer cust = qry.Skip(index).FirstOrDefault(); // 2nd round-trip


我知道这是旧的,但如果你从一个大表中选择许多随机行,请看:http://msdn.microsoft.com/en-us/library/cc441928.aspx我不知道是否有LINQ当量.
如果是*过滤器后30k*,我会说不:不要使用这种方法.做2次往返; 1获取Count(),1获得随机行...
@Neal S.:ctx.Random()的订单可以与Take(5)混合使用; 但如果您使用Count()方法,我预计6次往返是最简单的选择.

2> Konstantin T..:

实体框架的另一个示例:

var customers = db.Customers
                  .Where(c => c.IsActive)
                  .OrderBy(c => Guid.NewGuid())
                  .FirstOrDefault();

这不适用于LINQ to SQL.在OrderBy简单地被丢弃.


这在LINQ to SQL中不起作用......也许它在Entity Framework 4中工作(不确认).如果要对List进行排序,则只能使用.OrderBy和Guid.使用DB它将无法正常工作.
您有没有对此进行分析并确认它有效?在我使用LINQPad的测试中,order by子句被删除.
只是为了最终确认这在EF4中有效 - 在这种情况下它是很好的选择.

3> Jon Skeet..:

编辑:我只是注意到这是LINQ to SQL,而不是LINQ to Objects.使用Marc的代码让数据库为您完成此操作.我在这里留下这个答案作为LINQ to Objects的潜在兴趣点.

奇怪的是,你实际上并不需要计算.但是,除非得到计数,否则你需要获取每个元素.

你能做的就是保持"当前"值和当前计数的概念.当你获取下一个值时,取一个随机数并用"new"替换"current",概率为1/n,其中n是计数.

因此,当您读取第一个值时,您始终将其设为"当前"值.当您读取第二个值时,您可能会将其设为当前值(概率1/2).当你读取第三个值时,你可能会得到当前值(概率1/3)等等.当你的数据用完时,当前值是你读过的所有值中的随机值,具有统一的概率.

要在条件中应用它,只需忽略任何不符合条件的东西.最简单的方法是首先考虑"匹配"序列,首先应用Where子句.

这是一个快速实现.我觉得没关系......

public static T RandomElement(this IEnumerable source,
                                 Random rng)
{
    T current = default(T);
    int count = 0;
    foreach (T element in source)
    {
        count++;
        if (rng.Next(count) == 0)
        {
            current = element;
        }            
    }
    if (count == 0)
    {
        throw new InvalidOperationException("Sequence was empty");
    }
    return current;
}


仅供参考 - 我进行了快速检查,这个函数确实具有统一的概率分布(递增计数与Fisher-Yates shuffle的机制基本相同,所以它应该是合理的).

4> Ian Mercer..:

实现高效实现的一种方法是在数据Shuffle中添加一个用随机int填充的列(当创建每个记录时).

以随机顺序访问表的部分查询是......

Random random = new Random();
int seed = random.Next();
result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); // ^ seed);

这在数据库中执行XOR操作,并按XOR的结果进行排序.

好处:-

    高效:SQL处理排序,无需获取整个表

    可重复:(适合测试) - 可以使用相同的随机种子生成相同的随机顺序

这是我的家庭自动化系统用于随机化播放列表的方法.它每天都会选择一个新的种子,在白天提供一致的顺序(允许轻松的暂停/恢复功能),但每个新的一天都要重新审视每个播放列表.



5> Artur Keyan..:

如果你想var count = 16从表中获得例如随机行,你可以写

var rows = Table.OrderBy(t => Guid.NewGuid())
                        .Take(count);

这里我使用EF,表是Dbset

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有