3

私が得ている応答時間は約200msです。もっと最適化したい。どうすればこれを達成できますか?

CREATE OR REPLACE
PROCEDURE GETSTORES
(
LISTOFOFFERIDS IN VARCHAR2,
REF_OFFERS OUT TYPES.OFFER_RECORD_CURSOR
)
AS
BEGIN
  OPEN REF_OFFERS FOR
  SELECT
  /*+ PARALLEL(STORES 5) PARALLEL(MERCHANTOFFERS 5)*/
  MOFF.OFFERID,
  s.STOREID,
  S.LAT,
  s.LNG
  FROM
  MERCHANTOFFERS MOFF
  INNER JOIN STORES s ON MOFF.STOREID =S.STOREID
  WHERE
  MOFF.OFFERID IN
  (
    SELECT
      REGEXP_SUBSTR(LISTOFOFFERIDS,'[^,]+', 1, LEVEL)
    FROM
      DUAL CONNECT BY REGEXP_SUBSTR(LISTOFOFFERIDS, '[^,]+', 1, LEVEL) IS NOT NULL
  )
  ;
END
GETSTORES;

regex_substrを使用して、LISTOFOFFERIDSに含まれるコンマ区切りの文字列からOfferIDのリストを取得しています。StoresテーブルのSTOREIDにインデックスを作成しましたが、役に立ちません。同じことを達成するための新しいアプローチも、それが高速であれば問題ありません。

同じの型宣言:

create or replace

    PACKAGE TYPES
    AS
    TYPE OFFER_RECORD
    IS
      RECORD(
      OFFER_ID MERCHANTOFFERS.OFFERID%TYPE,
      STORE_ID STORES.STOREID%TYPE,
      LAT STORES.LAT%TYPE,
      LNG STORES.LNG%TYPE
      );
    TYPE OFFER_RECORD_CURSOR
    IS
      REF
      CURSOR
        RETURN OFFER_RECORD;
      END
      TYPES;

選択の計画は、次の情報を明らかにします。

Plan hash value: 1501040938

-------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                |   276 | 67620 |    17  (12)| 00:00:01 |
|*  1 |  HASH JOIN                                 |                |   276 | 67620 |    17  (12)| 00:00:01 |
|   2 |   NESTED LOOPS                             |                |       |       |            |          |
|   3 |    NESTED LOOPS                            |                |   276 | 61272 |     3  (34)| 00:00:01 |
|   4 |     VIEW                                   | VW_NSO_1       |     1 |   202 |     3  (34)| 00:00:01 |
|   5 |      HASH UNIQUE                           |                |     1 |       |     3  (34)| 00:00:01 |
|*  6 |       CONNECT BY WITHOUT FILTERING (UNIQUE)|                |       |       |            |          |
|   7 |        FAST DUAL                           |                |     1 |       |     2   (0)| 00:00:01 |
|*  8 |     INDEX RANGE SCAN                       | OFFERID_INDEX  |   276 |       |     0   (0)| 00:00:01 |
|   9 |    TABLE ACCESS BY INDEX ROWID             | MERCHANTOFFERS |   276 |  5520 |     0   (0)| 00:00:01 |
|  10 |   TABLE ACCESS FULL                        | STORES         |  9947 |   223K|    13   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("MERCHANTOFFERS"."STOREID"="STORES"."STOREID")
   6 - filter( REGEXP_SUBSTR ('M1-Off2,M2-Off5,M2-Off9,M5-Off4,M10-Off1,M1-Off3,M2-Off4,M3-Off2,M4-Of
              f6,M5-Off1,M6-Off1,M8-Off1,M7-Off3,M1-Off1,M2-Off1,M3-Off1,M3-Off4,M3-Off5,M3-Off6,M4-Off1,M4-Off7,M2
              -Off2,M3-Off3,M5-Off2,M7-Off1,M7-Off2,M1-Off7,M2-Off3,M3-Off7,M5-Off5,M4-Off2,M4-Off3,M4-Off5,M8-Off2
              ,M6-Off2,M1-Off5,M1-Off6,M1-Off9,M1-Off8,M2-Off6,M2-Off7,M4-Off4,M9-Off1,M6-Off4,M1-Off4,M1-Off10,M2-
              Off8,M3-Off8,M6-Off3,M5-Off3','[^,]+',1,LEVEL) IS NOT NULL)
   8 - access("MERCHANTOFFERS"."OFFERID"="$kkqu_col_1")
4

3 に答える 3

1
  1. サーバーがそれをサポートしている場合(必要と思われる場合)、ヒントをに変更し/*+ PARALLEL(S 8) PARALLEL(MOFF 8)*/ます。エイリアスがある場合は、ヒントでエイリアスを使用する必要があります。
  2. STORES(STOREID, LAT, LNG)APC( )によって提案された複合インデックスを試す必要があります
  3. 質問に答えてください。提示された例では、取得する個別のストアの数(select count(distinct storeid) from (your_query))と、STORESテーブルにあるストアの数を教えてください。(Select count(*) from Stores)?
  4. テーブルを分析しましたdbms_stats.gather_table_statsか?
  5. connect byクエリは問題ではないと思います。0.02秒で実行されます。
于 2012-09-27T06:18:46.640 に答える
0

結合が迅速に行われるように、結合に正規表現をドロップすることを検討してください。
結合列にインデックスがある場合、結合がネストされたループからある種のハッシュ結合に移動する可能性があります。

その結果セット(できれば行数が少ない)を取得したら、正規表現でフィルター処理します。

このシーンでは、WITHステートメントが役立つ場合があります。

このオーダーの何か。(テストされていない例)

WITH
base AS
(
    SELECT /*+ PARALLEL(STORES 5) PARALLEL(MERCHANTOFFERS 5) */
           moff.OFFERID,
              s.STOREID,
              s.LAT,
              s.LNG
    FROM MERCHANTOFFERS moff
    INNER JOIN STORES s 
    ON MOFF.STOREID = S.STOREID
),
offers AS
(
    SELECT REGEXP_SUBSTR(LISTOFOFFERIDS,'[^,]+', 1, LEVEL) offerid
    FROM DUAL 
    CONNECT BY REGEXP_SUBSTR(LISTOFOFFERIDS, '[^,]+', 1, LEVEL) IS NOT NULL
)
SELECT base.*
FROM base,
     offers
WHERE base.offerid = offers.offerid

Oracleは、2つのビューをメモリテーブルに実行してから結合する場合があります。

保証はありません。マイレージは異なる場合があります。あなたはアイデアを探していました。これはアイデアです。幸運を祈ります。

ヒントの章を正しく思い出せば、テーブル名にエイリアスを付けるときは、ヒントでそのエイリアスを使用する必要があります。/ * + PARALLEL(s 5)PARALLEL(moff 5)* /

ヒントの値を5に決めた理由について知りたいと思います。システムの負荷やその他の不思議な状況に応じて、Oracleが最適な値を選択するという印象を受けました。

于 2012-09-26T16:07:56.903 に答える
0

You Explain Plan を見ると、各ステップのタイミングは同じです。チューニングに焦点を当てる明確な候補はありません。

投稿したサンプルには、OFFERID の 50 個のトークンがあります。その代表は?それらは 276 STORES にマップされます。これは代表的な比率ですか? 複数のストアにヒットするオファーはありますか?

276 行は、行の約 2.7% であり、わずかなスライバーです。ただし、STORES は非常にコンパクトなテーブルのように見えるため、インデックス付きの読み取りが完全なテーブル スキャンよりも高速になるかどうかは微妙です。

データベースからより多くのジュースを絞り出すためにできる唯一の明白な方法は、STORES(STOREID, LAT, LNG); に複合インデックスを作成することです。おそらく、多くの DML を参照するテーブルではないため、追加のインデックスのオーバーヘッドはそれほど大きくありません。

最後のポイント: クエリは 0.2 秒で実行されます。では、どれくらい速くしたいですか?

于 2012-09-25T15:29:56.230 に答える