[英]How to select first 'N' records from a database containing million records?
我有一個填充了百萬條記錄的oracle數據庫。 我正在嘗試編寫一個SQL查詢,該查詢根據特定條件從數據庫返回第一個“N”個排序記錄(比如100條記錄)。
SELECT *
FROM myTable
Where SIZE > 2000
ORDER BY NAME DESC
然后以編程方式選擇前N個記錄。
這種方法的問題是:
我的問題是:
如果您的目的是找到100個隨機行並在之后對它們進行排序,那么Lasse的解決方案是正確的。 如果我認為您希望按名稱排序前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個隨機行,然后對它們進行排序。
這顯示了如何根據您的Oracle版本選擇前N行。
從Oracle 9i開始,RANK()和DENSE_RANK()函數可用於確定TOP N行。 例子:
根據工資獲得前10名員工
SELECT ename,sal FROM(SELECT ename,sal,RANK()OVER(ORDER BY sal DESC)sal_rank FROM emp)WHERE sal_rank <= 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 <= 10;
添加這個:
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> 2000,我不在乎哪100”。
這真的是你想要的嗎?
不,你實際上不會得到隨機結果,因為每次查詢服務器時它都會改變,但是你受到查詢優化器的支配。 如果該表的數據加載和索引統計信息隨時間發生變化,則在某些時候,您可能會獲得與上一個查詢不同的數據。
您的問題是每次運行查詢時都要進行排序。 您可以通過使用索引來消除排序操作 - 優化器可以使用索引來消除排序操作 - 如果排序列聲明為NOT NULL。
(如果列可以為空,則仍然可以通過(a)向查詢添加NOT NULL謂詞,或(b)添加基於函數的索引並相應地修改ORDER BY子句來實現。
僅供參考,在Oracle 12c中,可以使用FETCH
子句完成此任務。 您可以在此處查看有關此事項的示例和其他參考鏈接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.