2017-04-24 10 views
0

ページングにROWNUMBER関数を使用するSQLのパフォーマンスが低いです。ページサイズは5000に設定されていましたが、100に変更されました。低環境でのテストでは、この変更後の応答時間が7秒から1秒に短縮されました。SQL ROWNUMBER効率

しかし、クエリにはフィルタがあまり多くないため、たとえば、述語のLAST_UPD_DTが今日に設定されていると、完全なテーブルスキャンが行われる可能性があります。

このような状況では、ROWNUMBERをはるかに低い値のヘルプに設定したり、少しの違いを作ったりしますか?

プロダクションには約250万のレコードがあり、テストでは約5kのレスポンスが7秒から1秒に下がったことがわかりました。

クエリは、述語と同じ列を持つインデックスを使用します。現在、ORIG_TIME列には索引はありませんが、追加されます。データベースはDB2です。

以下は、問題の基本的なエッセンスを保持するクエリのトリムダウンバージョンです。

SELECT * 
    FROM 
     ( 
     SELECT ROWNUMBER () OVER ( 
     ORDER BY MEMBERS.ORIG_TIME ASC), 
       MEMBERS.APP_ID, 
       MEMBERS.NAME 
     FROM MEMBERS 
     WHERE 
      MEMBERS.LAST_UPD_DT <= ? AND 
      (MEMBERS.STAT_CD = 'S' OR MEMBERS.CURR_STAT = 'D') 
     ORDER BY MEMBERS.ORIG_TIME ASC 
    ) 
     AS TEMP_ 
    WHERE ROWNUMBER_ <= 100 --used to be 5000 

ご意見やご協力をいただければ幸いです。ありがとうございました。

+0

は 'last_upd_dt'フィールドインデックスされますか?もしそうなら、あなたはなぜテーブルスキャンがあると思いますか? –

+0

@ダンブルクックはいそうです。おそらく私は間違っていますが、クエリが大量のレコードをテーブルから戻した場合、オプティマイザはインデックス検索よりもテーブルスキャンを実行する方が効率的ではないと判断して、テーブルからデータを読み込みます。 subselectの 'ORDER BY MEMBERS.ORIG_TIME ASC'は – scifi2008

+0

です。その注文が必要な場合は、外側の選択の後に置く。 – mustaccio

答えて

0

あなたにインデックスを追加して、それのようにクエリを修正:

SELECT * 
FROM 
    ( 
    SELECT ROWNUMBER () OVER (ORDER BY MEMBERS.ORIG_TIME ASC) as RANG, 
      MEMBERS.APP_ID, MEMBERS.NAME 
    FROM MEMBERS 
    WHERE 
    MEMBERS.LAST_UPD_DT <= ? AND (MEMBERS.STAT_CD = 'S' OR MEMBERS.CURR_STAT = 'D') 
) 
    AS TEMP 
WHERE RANG between 1 AND 5000 -- Modify here your range 
order by RANG