我有一个填充了百万条记录的oracle数据库。我正在尝试编写一个SQL查询,根据特定条件从数据库中返回第一个“N”个排序记录(比如说100个记录)。
SELECT *
FROM myTable
Where SIZE > 2000
ORDER BY NAME DESC
然后以编程方式选择前N个记录。
这种方法的问题是:
我的问题是:
答案 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有关此问题的示例和其他参考链接。