【问题标题】:Select a random sample of results from a query result从查询结果中选择随机结果样本
【发布时间】:2010-10-18 12:47:13
【问题描述】:

This question 询问有关在 SQL Server 上获取随机(ish)记录样本的问题,答案是使用 TABLESAMPLE。 Oracle 10 中是否有等价物?

如果没有,是否有从查询集中获取随机结果样本的标准方法?例如,如何从正常返回数百万的查询中获取 1,000 行随机数?

【问题讨论】:

    标签: sql oracle random-sample


    【解决方案1】:
    SELECT  *
    FROM    (
            SELECT  *
            FROM    mytable
            ORDER BY
                    dbms_random.value
            )
    WHERE rownum <= 1000
    

    【讨论】:

    • DBMS_RANDOM是PL/SQL,Oracle中没有纯SQL方式生成随机数。所有冰雹上下文切换。
    • 在具有 40'000 行的表上,此查询需要 0.1 秒,而基于 SAMPLE(n) 的查询需要 0.02 秒(快 5 倍)。所以对于我的数据量来说,它并没有那么慢......
    【解决方案2】:

    SAMPLE clause 将为您提供表中所有行的随机样本百分比。

    例如,这里我们获取了 25% 的行:

    SELECT * FROM emp SAMPLE(25)
    

    以下 SQL(使用其中一个分析函数)将为您提供一个随机样本,其中包含表中特定值(类似于 GROUP BY)每次出现的特定数量。

    我们在这里分别抽取 10 个样本:

    SELECT * FROM (
    SELECT job, sal, ROW_NUMBER()
    OVER (
    PARTITION BY job ORDER BY job
    ) SampleCount FROM emp
    )
    WHERE SampleCount <= 10
    

    【讨论】:

    • 我们大部分时间都没有得到 25% 的行。相反,我们得到了一些不确定的行数。我们原始集合中的每一行都有相同的机会(此处为 ¼)被选中。
    • SEED(n) 选项允许您始终获得相同的样本,从而获得相同的行数(这在您需要可重现的结果时可能很有用),例如SELECT * from emp SAMPLE(25) SEED(1).
    • 使用一个有 40'000 行和SAMPLE(25) 的表,我看到有 24.41% 到 25.36% 的记录被返回。
    【解决方案3】:

    这不是一个完美的答案,但会获得更好的性能。

    SELECT  *
    FROM    (
        SELECT  *
        FROM    mytable sample (0.01)
        ORDER BY
                dbms_random.value
        )
    WHERE rownum <= 1000
    

    Sample 将为您提供实际表格的百分比,如果您真的想要 1000 行,则需要调整该数字。更常见的是,无论如何我只需要任意数量的行,所以我不会限制我的结果。在我有 200 万行的数据库上,我得到 2 秒和 60 秒。

    select * from mytable sample (0.01)
    

    【讨论】:

    • 如果样本要在统计上无偏,这不是一个好方法。由于内部查询的结果是有序的,因此第一个值比后一个值更有可能被选中。试想一下,表的最后一个寄存器被选中是多么不可能!
    • 因为内部查询按未索引值排序。在返回第一行之前,数据库必须一直计算到最后一行的值。因为它与任何其他记录一样有可能首先被选中。
    • @Baumann : dbms_random.value 是数据库生成的随机值,因此不应认为行是真正有序的(只是让@选择的每一行987654324@ 以相同的概率出现在 1000 个返回的行中)。
    • 第一个查询结合了两全其美(SAMPLE(n) 的快速随机选择和rownum&lt;=1000 精确定义的返回结果数量)。
    • 就我而言,我想利用现有的生产表来创建一些真实的测试数据。通过调整样本大小,这正是我所需要的。
    【解决方案4】:
    SELECT * FROM TABLE_NAME SAMPLE(1)
    

    会给你一个大约 1% 的份额,而不是观察次数的 1/100。可能的原因是 Oracle 会为每个观察生成一个随机标志,以确定是否包含在它生成的样本中。在这样的生成过程中,参数 1 (1%) 扮演了每个观察被选入样本的概率的角色。

    如果这是真的,样本量的实际分布将是二项式的。

    【讨论】:

      【解决方案5】:

      我知道这已经得到解答,但是看到这里有这么多访问,我想添加一个使用 SAMPLE 子句但仍允许先过滤行的版本:

      with cte1 as (
          select *
          from t_your_table
          where your_column = 'ABC'
      )
      select * from cte1 sample (5)
      

      但请注意,基本选择需要 ROWID 列,这意味着它可能不适用于某些视图。

      【讨论】:

        【解决方案6】:

        样本函数用于ORACLE中的样本数据。所以你可以这样尝试:-

        SELECT * FROM TABLE_NAME SAMPLE(50);
        

        这里的 50 是表中包含的数据的百分比。因此,如果您想要 100000 中的 1000 行。您可以执行如下查询:

        SELECT * FROM TABLE_NAME SAMPLE(1);
        

        希望对你有帮助。

        【讨论】:

          【解决方案7】:

          这样的事情应该可以工作:

          SELECT * 
          FROM table_name
          WHERE primary_key IN (SELECT primary_key 
                                FROM
                                (
                                  SELECT primary_key, SYS.DBMS_RANDOM.RANDOM 
                                  FROM table_name 
                                  ORDER BY 2
                                )
                                WHERE rownum <= 10 );
          

          【讨论】:

            【解决方案8】:

            我们被分配从代理列表中仅选择两条记录..即在一周的跨度内为每个代理选择 2 条随机记录等....以下是我们得到的并且它有效

            with summary as (
            Select Dbms_Random.Random As Ran_Number,
                         colmn1,
                         colm2,
                         colm3
                         Row_Number() Over(Partition By col2 Order By Dbms_Random.Random) As Rank
                From table1, table2
             Where Table1.Id = Table2.Id
             Order By Dbms_Random.Random Asc)
            Select tab1.col2,
                         tab1.col4,
                         tab1.col5,
                From Summary s
             Where s.Rank <= 2;
            

            【讨论】:

              【解决方案9】:

              假设您正试图从名为 my_table 的表中准确选择 1,000 个随机行。这是一种方法:

              select
                  *
              from
                  (
                      select
                          row_number() over(order by dbms_random.value) as random_id,
                          x.*
                      from
                          my_table x
                  )
              where
                  random_id <= 1000
              ;
              

              这与@Quassnoi 发布的答案略有不同。它们都具有相同的成本和执行时间。唯一的区别是您可以选择用于获取样本的随机数。

              【讨论】:

                猜你喜欢
                • 2020-12-27
                • 2016-05-21
                • 1970-01-01
                • 1970-01-01
                • 2012-01-03
                • 2015-04-12
                • 1970-01-01
                • 2012-11-30
                • 1970-01-01
                相关资源
                最近更新 更多