如何从包含百万条记录的数据库中选择第一个“N”条记录?

时间:2009-09-11 09:53:04

标签: sql oracle sorting sql-order-by

我有一个填充了百万条记录的oracle数据库。我正在尝试编写一个SQL查询,根据特定条件从数据库中返回第一个“N”个排序记录(比如说100个记录)。

SELECT * 
FROM myTable 
Where SIZE > 2000 
ORDER BY NAME DESC

然后以编程方式选择前N个记录。

这种方法的问题是:

  • 查询结果为五十万 记录和“按名称排序”的原因 所有要在NAME上按降序排序的记录。这种分类花费了大量时间。 (将近30-40秒。如果我省略ORDER BY,则只需1秒钟。)
  • 在我感兴趣的那种之后 只有前N(100)条记录。因此,对完整记录进行排序是没有用的。

我的问题是:

  1. 是否可以指定'N' 查询本身? (这样排序只适用于N条记录,查询变得更快)。
  2. 在SQL中有任何更好的方法来改进查询以进行排序 只有N个元素并快速返回 时间。

5 个答案:

答案 0 :(得分:19)

如果你的目的是找到100个随机行并在之后对它们进行排序,那么Lasse's solution是正确的。如果我认为您希望按名称排序前100行而丢弃其他行,则可以构建如下查询:

SELECT * 
  FROM (SELECT * 
          FROM myTable 
         WHERE SIZE > 2000 ORDER BY NAME DESC) 
 WHERE ROWNUM <= 100

优化器将理解它是一个TOP-N查询,并且能够在NAME上使用索引。它不必对整个结果集进行排序,它只是从索引的末尾开始并向后读取并在100行后停止。

您还可以在原始查询中添加提示,让优化程序了解您只对第一行感兴趣。这可能会生成类似的访问路径:

SELECT /*+ FIRST_ROWS*/* FROM myTable WHERE SIZE > 2000 ORDER BY NAME DESC

修改只是将AND rownum <= 100添加到查询中将无法正常工作,因为在Oracle rownum中归于排序之前:这就是为什么你必须使用子查询。如果没有子查询,Oracle将选择100个随机行,然后对它们进行排序。

答案 1 :(得分:5)

This显示了如何根据您的Oracle版本选择前N行。

  

从Oracle 9i开始,RANK()和   可以使用DENSE_RANK()函数   确定TOP N行。例子:

     

获得前10名员工   他们的工资

     

SELECT ename,sal FROM(SELECT   ename,sal,RANK()OVER(订购sal   DESC)sal_rank              FROM emp)WHERE sal_rank&lt; = 10;

     

选择排名前10的员工   薪金

     

SELECT ename,sal FROM(SELECT   ename,sal,DENSE_RANK()OVER(ORDER   BY sal DESC)sal_dense_rank              FROM emp)WHERE sal_dense_rank&lt; = 10;

两者之间的差异解释为here

答案 2 :(得分:4)

添加:

 AND rownum <= 100

到您的WHERE子句。

但是,这不符合您的要求。

如果要选择100个随机行,对它们进行排序,然后返回它们,则必须首先制定不带ORDER BY的查询,然后将其限制为100行,然后从中进行选择并排序。

可以工作,但遗憾的是我没有可用于测试的Oracle服务器:

SELECT *
FROM (
    SELECT *
    FROM myTable
    WHERE SIZE > 2000
      AND rownum <= 100
    ) x
ORDER BY NAME DESC

但请注意那里的“随机”部分,你说“给我100行SIZE&gt; 2000,我不在乎哪100”。

这真的是你想要的吗?

不,你实际上不会得到随机结果,因为每次查询服务器时它都会改变,但是你受到查询优化器的支配。如果该表的数据加载和索引统计信息随时间发生变化,则在某些时候您可能获得的数据与上一个查询中的数据不同。

答案 3 :(得分:0)

您的问题是每次运行查询时都要进行排序。您可以通过使用索引来消除排序操作 - 优化器可以使用索引来消除排序操作 - 如果已排序的列被声明为NOT NULL。

(如果该列可以为空,则仍然可以通过(a)向查询添加NOT NULL谓词,或者(b)添加基于函数的索引并相应地修改ORDER BY子句来实现。

答案 4 :(得分:0)

仅供参考,在Oracle 12c中,可以使用FETCH子句完成此任务。您可以查看here有关此问题的示例和其他参考链接。