問題を引き起こしているトップ N クエリがあります。
まず、次のようなクエリがあります。
select /*+ gather_plan_statistics */ * from
(
select rowid
from payer_subscription ps
where ps.subscription_status = :i_subscription_status
and ps.merchant_id = :merchant_id2
order by transaction_date desc
) where rownum <= :i_rowcount;
このクエリはうまく機能します。Merchant_id、subscription_status、transaction_date のインデックスを使用して、大規模なデータ セットの上位 10 行を非常に効率的に見つけることができます。
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 4 |
|* 1 | COUNT STOPKEY | | 1 | | 10 |00:00:00.01 | 4 |
| 2 | VIEW | | 1 | 11 | 10 |00:00:00.01 | 4 |
|* 3 | INDEX RANGE SCAN DESCENDING| SODTEST2_IX | 1 | 100 | 10 |00:00:00.01 | 4 |
-------------------------------------------------------------------------------------------------------
ご覧のとおり、各段階で実際に推定される行数は 10 で、これは正しい値です。
ここで、merchant_id のセットの上位 N レコードを取得する必要があるため、クエリを変更して 2 つの Merchant_id を含めると、パフォーマンス タンクは次のようになります。
select /*+ gather_plan_statistics */ * from
(
select rowid
from payer_subscription ps
where ps.subscription_status = :i_subscription_status
and (ps.merchant_id = :merchant_id or
ps.merchant_id = :merchant_id2 )
order by transaction_date desc
) where rownum <= :i_rowcount;
----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.17 | 178 | | | |
|* 1 | COUNT STOPKEY | | 1 | | 10 |00:00:00.17 | 178 | | | |
| 2 | VIEW | | 1 | 200 | 10 |00:00:00.17 | 178 | | | |
|* 3 | SORT ORDER BY STOPKEY| | 1 | 200 | 10 |00:00:00.17 | 178 | 2048 | 2048 | 2048 (0)|
| 4 | INLIST ITERATOR | | 1 | | 42385 |00:00:00.10 | 178 | | | |
|* 5 | INDEX RANGE SCAN | SODTEST2_IX | 2 | 200 | 42385 |00:00:00.06 | 178 | | | |
----------------------------------------------------------------------------------------------------------------------------
2 つのインデックス レンジ スキャンから 42K 行が出力されていることに注意してください。10 行に達しても、Oracle はインデックス レンジ スキャンを中止しなくなりました。私が考えたのは、Oracle は各 Merchant_id に対して最大 10 行を取得し、クエリによって最大 10 行が返されることを知っているということです。次に、その 10 + 10 行を並べ替え、トランザクションの日付に基づいて上位 10 行を出力しますが、それを拒否します。
マーチャントのリストをクエリに渡す必要があるときに、最初のクエリのパフォーマンスを取得する方法を知っている人はいますか? おそらくユニオンオールを使用してパフォーマンスを得ることができますが、マーチャントのリストは可変であり、1 つまたは 2 つから数 100 の間のどこかにある可能性があります。