2010-03-01 43 views
2

我想从随机表中获取1000条记录,所以我用:问题使用ROW_NUMBER()来获得随机记录(SQL Server 2005中)

SELECT top 1000 
     mycol1 
    , mycol2 
    , ROW_NUMBER() OVER (ORDER BY NEWID()) rn 
FROM mytable 

不过,我不希望看到rn在我的结果集,所以我这样做:

SELECT mycol1 
    , mycol2 
FROM (
    SELECT top 1000 
      mycol1 
     , mycol2 
     , ROW_NUMBER() OVER (ORDER BY NEWID()) rn 
    FROM mytable 
) a 

当我这样做时,结果不会随机出现。他们来了,就好像我刚才所说的使用row_number()的顶级10000 没有随机化。

当我查询更改为

SELECT mycol1 
    , mycol2 
    , rn 
FROM (
    SELECT top 1000 
      mycol1 
     , mycol2 
     , ROW_NUMBER() OVER (ORDER BY NEWID()) rn 
    FROM mytable 
) a 

他们是随机的一次。

我猜sql server做了某种优化,说:“嘿,这家伙不需要列rn,所以只是忽略它”。但在这种情况下,这会导致意外行为。有什么办法可以避免这种情况? PS:我使用ROW_NUMBER()技巧,因为mytable有10 mio。行和

SELECT top 10000 * 
FROM mytable 
ORDER BY NEWID() 

永远运行,而与ROW_NUMBER()它只需要长达30秒。

+1

喜欢你的“ROW_NUMBER()OVER(ORDER BY NEWID())”。几次使用这个效果很好。 – 2014-11-06 21:24:13

回答

2

您也可以尝试使用一些小的RN场在那里同样

WHERE子句在外部查询RN> 0,这将可能迫使编译通过,以使RN领域。

此外,我认为如果你想随机抽样你的整个数百万条记录,你的整体查询将成为一个问题。这将只抓住“第一次离开磁盘”的记录块,虽然不保证是相同的往往不会是相同的10000.

我会建议创建一个10,000(MINI(PrimaryKey)和MAX(PrimaryKey的),然后做一个WHERE的PrimaryKey IN(...)或类似

+0

感谢您指出它只会抓取表格的一部分。然而,在这个例子中,我可以忍受它。 – ercan 2010-03-01 12:02:55

+0

他可以添加WHERE <= 1000获得前1000名并解决问题 – 2017-02-09 21:14:37

1

添加类似其中RN不为空到外查询,以便RN它包含在查询计划,而不是优化出

0

我一直在努力解决这个问题。我用CROSS APPLY和TOP解决了它。请记住,CROSS APPLY将我的外表拉到派生表的范围内,我知道必须有一种方法来执行此操作。

以下代码导致根据制造商添加3(*)随机相关产品。

INSERT INTO  ProductGroup (
        ParentId, 
        ChildId 
       ) 
SELECT   DISTINCT 
       P.ProductId, 
       CandidateInner.ChildId 
FROM   ProductRelated PR 
JOIN   Product P 
ON    PR.ChildId = P.ProductId 
CROSS APPLY  
       ( 
        SELECT  DISTINCT TOP 3 
           NewId() AS RandId, 
           Product.ManufacturerId, 
           ProductRelated.ChildId 
        FROM  ProductRelated 
        JOIN  Product 
        ON   Product.ProductId = ProductRelated.ChildId 
        WHERE  ManufacturerId IS NOT NULL 
        AND   Product.ManufacturerId = P.ManufacturerId 
        ORDER BY NewId() 
       ) CandidateInner 
LEFT JOIN  (
        SELECT  DISTINCT TOP 100 PERCENT 
           ParentId, 
           COUNT(DISTINCT ChildId) AS Ct 
        FROM  ProductGroup 
        GROUP BY ParentId 
        HAVING  COUNT(DISTINCT ChildId) >= 3 
       ) AlreadyGrouped 
ON    P.ProductId = AlreadyGrouped.ParentId 
WHERE   P.ProductId <> CandidateInner.ChildId 
AND    AlreadyGrouped.ParentId IS NULL 
ORDER BY  P.ProductId 

*请注意,这将在如下2种情况插入少于3:

1)凡有< 3制造商 2)(有问题的)相关的产品,该随机前3的回报相同的产品本身。 (1)以上是不可避免的。

我上面处理(2)的方式是运行两次,然后删除重复项。这仍然不是100%,但从统计上来说,这对我的要求绰绰有余。这是在一个夜间运行的脚本中,但我仍然喜欢在CROSS APPLY之外快速 - 任何拉动范围检查的东西都会导致制造商连接导致的派生表的扫描,即使将其拉入内部将意味着(2)不再是一个问题,但是对于适当的指数来说,它的速度比较慢。