私たちのWebサーバ上のすべての履歴アクティビティを含むデータベースからApache要求を引き出し、必要に応じて迅速に回帰するためのインフラストラクチャを構築しようとしています。私たちは依然として小規模のクライアントからの要求を後退させることによってカバレッジを向上させるために、各クライアントに対する最大n個の要求(この質問のために、言い換えれば10個)を取得することによって要求を分散したいと考えています。グループごとの最大n個のSQLクエリへの高性能アプローチ
ここでは、最も近いものがSQL query to return top N rows per ID across a range of IDsであるように思われる多くの類似した質問が見つかりましたが、回答はほとんど私がすでに試したパフォーマンスに依存しない解決策でした。この表は、特定の日のために数百万のエントリが含まれており、このアプローチは、すべての行を読み込む必要ことを考えると、しかし
SELECT
*
FROM
(
SELECT
dailylogdata.*,
row_number() over (partition by dailylogdata.contextid order by occurrencedate) rn
FROM
dailylogdata
WHERE
shorturl in (?)
)
WHERE
rn <= 10;
:たとえば、ROW_NUMBER()解析関数は、私たちが探している正確にデータを取得しますrow_number分析関数を適用するために私たちの選択基準に一致するインデックスがある場合、パフォーマンスはひどいです。私たちは、彼らのROW_NUMBERは、上記のクエリを実行してから10統計を超えたためにのみそれらの大半を捨てるために、ほぼ万行を選択して終了:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp||
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|| 0 | SELECT STATEMENT | | 1 | | 12222 |00:09:08.94 | 895K| 584K| 301 | | | | ||
||* 1 | VIEW | | 1 | 4427K| 12222 |00:09:08.94 | 895K| 584K| 301 | | | | ||
||* 2 | WINDOW SORT PUSHED RANK | | 1 | 4427K| 13536 |00:09:08.94 | 895K| 584K| 301 | 2709K| 743K| 97M (1)| 4096 ||
|| 3 | PARTITION RANGE SINGLE | | 1 | 4427K| 932K|00:22:27.90 | 895K| 584K| 0 | | | | ||
|| 4 | TABLE ACCESS BY LOCAL INDEX ROWID| DAILYLOGDATA | 1 | 4427K| 932K|00:22:27.61 | 895K| 584K| 0 | | | | ||
||* 5 | INDEX RANGE SCAN | DAILYLOGDATA_URLCONTEXT | 1 | 17345 | 932K|00:00:00.75 | 1448 | 0 | 0 | | | | ||
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| |
|Predicate Information (identified by operation id): |
|--------------------------------------------------- |
| |
| 1 - filter("RN"<=:SYS_B_2) |
| 2 - filter(ROW_NUMBER() OVER (PARTITION BY "DAILYLOGDATA"."CONTEXTID" ORDER BY "OCCURRENCEDATE")<=:SYS_B_2) |
| 5 - access("SHORTURL"=:P1) |
| |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
しかし、代わりに我々は唯一の最初の10件の結果を照会場合このクエリを実行しているから
SELECT
*
FROM
(
SELECT
dailylogdata.*
FROM
dailylogdata
WHERE
shorturl in (?)
and contextid = ?
)
WHERE
rownum <= 10;
統計:特定のContextIDのために、我々は劇的に速く、この実行することができます。この例では
|-------------------------------------------------------------------------------------------------------------------------|
|| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers ||
|-------------------------------------------------------------------------------------------------------------------------|
|| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 14 ||
||* 1 | COUNT STOPKEY | | 1 | | 10 |00:00:00.01 | 14 ||
|| 2 | PARTITION RANGE SINGLE | | 1 | 10 | 10 |00:00:00.01 | 14 ||
|| 3 | TABLE ACCESS BY LOCAL INDEX ROWID| DAILYLOGDATA | 1 | 10 | 10 |00:00:00.01 | 14 ||
||* 4 | INDEX RANGE SCAN | DAILYLOGDATA_URLCONTEXT | 1 | 1 | 10 |00:00:00.01 | 5 ||
|-------------------------------------------------------------------------------------------------------------------------|
| |
|Predicate Information (identified by operation id): |
|--------------------------------------------------- |
| |
| 1 - filter(ROWNUM<=10) |
| 4 - access("SHORTURL"=:P1 AND "CONTEXTID"=TO_NUMBER(:P2)) |
| |
+-------------------------------------------------------------------------------------------------------------------------+
を、Oracleがスマートです10の結果を得た後にデータを取り出すのを止めるのに十分です。 I は完全なcontextidsを収集し、各contextidに対してこのクエリの1つのインスタンスからなるクエリをプログラム的に生成することができますが、union all
は完全に混乱していますが、コンテキストの数が限られているため、たとえそうでなくても、このアプローチはクルーグを引き起こす。
2番目のクエリに見合ったパフォーマンスを維持しながら、最初のクエリのシンプルさを維持するアプローチを知っている人はいますか?また、私は実際には安定した行のセットを検索することには気をつけません。私の基準を満たしていれば、回帰の目的のために問題ありません。
編集: Adam Muschの提案がトリックでした。私は彼の答えにコメントの応答に合わせることができないので、ここで彼の変更を加えてパフォーマンス結果を追加しています。また、私はここに、この時間をテストするために、より大きなデータセットを使用しています(キャッシュ)の統計では、比較のために私の元ROW_NUMBERアプローチから、次のとおりです。
|-------------------------------------------------------------------------------------------------------------------------------------------------|
|| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem ||
|-------------------------------------------------------------------------------------------------------------------------------------------------|
|| 0 | SELECT STATEMENT | | 1 | | 12624 |00:00:22.34 | 1186K| 931K| | | ||
||* 1 | VIEW | | 1 | 1163K| 12624 |00:00:22.34 | 1186K| 931K| | | ||
||* 2 | WINDOW NOSORT | | 1 | 1163K| 1213K|00:00:21.82 | 1186K| 931K| 3036M| 17M| ||
|| 3 | TABLE ACCESS BY INDEX ROWID| TWTEST | 1 | 1163K| 1213K|00:00:20.41 | 1186K| 931K| | | ||
||* 4 | INDEX RANGE SCAN | TWTEST_URLCONTEXT | 1 | 1163K| 1213K|00:00:00.81 | 8568 | 0 | | | ||
|-------------------------------------------------------------------------------------------------------------------------------------------------|
| |
|Predicate Information (identified by operation id): |
|--------------------------------------------------- |
| |
| 1 - filter("RN"<=10) |
| 2 - filter(ROW_NUMBER() OVER (PARTITION BY "CONTEXTID" ORDER BY NULL)<=10) |
| 4 - access("SHORTURL"=:P1) |
+-------------------------------------------------------------------------------------------------------------------------------------------------+
私はアダムの提案ダウンビットを沸騰の自由を撮影しました。ここで変更クエリ...
select
*
from
twtest
where
rowid in (
select
rowid
from (
select
rowid,
shorturl,
row_number() over (partition by shorturl, contextid
order by null) rn
from
twtest
)
where rn <= 10
and shorturl in (?)
);
だ...そしてその(キャッシュ)の評価から統計:
宣伝として|--------------------------------------------------------------------------------------------------------------------------------------|
|| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem ||
|--------------------------------------------------------------------------------------------------------------------------------------|
|| 0 | SELECT STATEMENT | | 1 | | 12624 |00:00:01.33 | 19391 | | | ||
|| 1 | NESTED LOOPS | | 1 | 1 | 12624 |00:00:01.33 | 19391 | | | ||
|| 2 | VIEW | VW_NSO_1 | 1 | 1163K| 12624 |00:00:01.27 | 6770 | | | ||
|| 3 | HASH UNIQUE | | 1 | 1 | 12624 |00:00:01.27 | 6770 | 1377K| 1377K| 5065K (0)||
||* 4 | VIEW | | 1 | 1163K| 12624 |00:00:01.25 | 6770 | | | ||
||* 5 | WINDOW NOSORT | | 1 | 1163K| 1213K|00:00:01.09 | 6770 | 283M| 5598K| ||
||* 6 | INDEX RANGE SCAN | TWTEST_URLCONTEXT | 1 | 1163K| 1213K|00:00:00.40 | 6770 | | | ||
|| 7 | TABLE ACCESS BY USER ROWID| TWTEST | 12624 | 1 | 12624 |00:00:00.04 | 12621 | | | ||
|--------------------------------------------------------------------------------------------------------------------------------------|
| |
|Predicate Information (identified by operation id): |
|--------------------------------------------------- |
| |
| 4 - filter("RN"<=10) |
| 5 - filter(ROW_NUMBER() OVER (PARTITION BY "SHORTURL","CONTEXTID" ORDER BY NULL NULL)<=10) |
| 6 - access("SHORTURL"=:P1) |
| |
|Note |
|----- |
| - dynamic sampling used for this statement (level=2) |
| |
+--------------------------------------------------------------------------------------------------------------------------------------+
、我々は唯一の完全濾過行に対してdailylogdataテーブルにアクセスしています。私はそれがが表示されていることを懸念していますが、まだ選択している(1213K)行の数に基づいてurlcontextインデックスのフルスキャンを実行していますが、コンテキスト固有の結果の数を増やすと、これは誤解を招く可能性があります)。
同じ結果セット(グループごとに最大のN)を達成する他の方法やクエリを試したことがありますか? –
2番目のクエリは「最初の10行」を取得せず、単純に10行を半ランダムに取得します。最初のクエリの1つのパーティションと真に等しくするために、内側のクエリに 'order by'を追加する必要があります。 – Allan
ほとんどの場合、@ypercube同様のパフォーマンス結果を持つ他の分析関数を試しました。私は、必要なだけ多くの行を返さない[最初の](http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions056.htm#sthref1389)関数のようないくつかのより秘密のものを試しましたしかし、私はそれがこのクエリよりも優れていると思った。しかし、他の分析関数と同様に、必要以上にインデックスをスキャンしました。 – Trevor