2

問題を引き起こしているトップ 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 の間のどこかにある可能性があります。

4

3 に答える 3

1

use_concat が無視される場合が多い。参照: MOS 注: 異なるバージョンでの USE_CONCAT ヒント (Doc ID 259741.1)

USE_CONCATが機能しないOR_EXPANDを使用して、10.2.0.4、11.2.0.1で成功しました。/*+ OR_EXPAND( 別名 column_name ) */

ここに文書化されています: http://www.hellodba.com/reader.php?ID=199&lang=EN

于 2013-11-12T06:09:53.550 に答える
1

ヒントを使用--+ use_concatして、Oracle に UNION ALL であるかのようにクエリを実行させることができます。

ドキュメントから:

USE_CONCAT ヒントは、UNION ALL 集合演算子を使用して、クエリの WHERE 句の結合された OR 条件を複合クエリに変換するようオプティマイザに指示します。このヒントがない場合、この変換は、連結を使用したクエリのコストが、連結を使用しない場合のコストよりも安い場合にのみ発生します。USE_CONCAT ヒントは、コストの考慮事項をオーバーライドします。

于 2012-07-27T14:22:21.763 に答える
0

これが役立つかどうかはわかりませんが、OR 演算子を IN に置き換えてみてください。

and ps.merchant_id IN (:merchant_id, :merchant_id2)
于 2012-07-27T14:24:48.500 に答える