2016-04-26 5 views
0

。私は私にはないものを動作するようになっていると何この時点で困惑していると思うのOracleインデックスの行動についての詳細を学ぶました。オラクル:私は過去2日間に渡って効率的にこのクエリの作業を取得しようとしてきた最適化二回自己結合クエリ

基本的に、クエリは値を合計し、昨日と先週の値と比較しています。

私はそれを分解して遊んだ、私は私の心の分析クエリとインデックスの順序を変更するおもしろいが何も動作するようだ。すべての私のテストはすぐに私はそれだけで永遠にかかる20万行をテーブルの上にそれを実行するよう、500Kの行を持つテーブルにされています。

ご協力いただきまして誠にありがとうございます。

元の投稿を修正しました。 :)

CREATE TABLE TABLE_1 
(ORDER_LINE_ID NUMBER, OFFSET NUMBER, BREAK_ID NUMBER, ZONE NUMBER, NETWORK NUMBER, HOUR_OF_DAY NUMBER, START_TIME DATE, END_TIME DATE, SUCCESS NUMBER 
    CONSTRAINT "TABLE_1_PK" PRIMARY KEY (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, HOUR_OF_DAY)) 

-- SUCCESS is already aggregated during the insert 
-- These are last week's records 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (1,0,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (1,30,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 2); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (2,0,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (2,30,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1); 

-- These are yesterday's records 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (3,0,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (3,30,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 2); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (4,0,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (4,30,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1); 

-- This is today's records 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (5,0,1, 1, 1, 2016042701,'04/27/2016 00:00:00', '04/27/2016 02:00:00', 1); 
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS) 
VALUES (5,30,1, 1, 1, 2016042701,'04/27/2016 00:00:00', '04/27/2016 02:00:00', 1); 

-- Original twice join query 
SELECT BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME, SUM(SUCCESS), SUM(YESTERDAY_SUCCESS), SUM(LAST_WEEK_SUCCESS) 
FROM TABLE_1 CURRENT_DAY 
LEFT OUTER JOIN (
    SELECT SUM(SUCCESS) YESTERDAY_SUCCESS, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME FROM TABLE_1 
    GROUP BY ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME 
) YESTERDAY 
    ON YESTERDAY.START_TIME + 1 = CURRENT_DAY.START_TIME 
    AND YESTERDAY.END_TIME + 1 = CURRENT_DAY.END_TIME 
    AND YESTERDAY.HOUR_OF_DAY = CURRENT_DAY.HOUR_OF_DAY 
    AND YESTERDAY.NETWORK = CURRENT_DAY.NETWORK 
    AND YESTERDAY.ZONE = CURRENT_DAY.ZONE 
LEFT OUTER JOIN (
    SELECT SUM(SUCCESS) LAST_WEEK_SUCCESS, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME FROM TABLE_1 
    GROUP BY ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME 
) LAST_WEEK 
    ON YESTERDAY.START_TIME + 7 = CURRENT_DAY.START_TIME 
    AND YESTERDAY.END_TIME + 7 = CURRENT_DAY.END_TIME 
    AND YESTERDAY.HOUR_OF_DAY = CURRENT_DAY.HOUR_OF_DAY 
    AND YESTERDAY.NETWORK = CURRENT_DAY.NETWORK 
    AND YESTERDAY.ZONE = CURRENT_DAY.ZONE 
GROUP BY BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME; 

-- Using Analytic Query (thank you to MT0) 
SELECT BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME, SUM(SUCCESS), SUM(YESTERDAY_SUCCESS), SUM(LAST_WEEK_SUCCESS) 
FROM (
    SUM(SUCCESS) 
    OVER (PARTITION BY ZONE, NETWORK, HOUR_OF_DAY, TO_CHAR(START_TIME, 'HH24:MI:SS'), TO_CHAR(END_TIME, 'HH24:MI:SS') 
      ORDER BY START_TIME 
      RANGE BETWEEN INTERVAL '1' DAY PRECDEDING AND INTERVAL '1' DAY PRECEDING 
     ) AS YESTERDAY_SUCCESS, 
SUM (SUCCESS) 
    OVER (PARTITION BY ZONE, NETWORK, HOUR_OF_DAY, TO_CHAR(START_TIME, 'HH24:MI:SS'), TO_CHAR(END_TIME, 'HH24:MI:SS') 
      ORDER BY START_TIME 
      RANGE BETWEEN INTERVAL '7' DAY PRECDEDING AND INTERVAL '7' DAY PRECEDING 
     ) AS LAST_WEEK_SUCCESS 
FROM TABLE_1 
) T1 
WHERE SYSDATE - INTERVAL '12' HOUR <= START_TIME 
AND START_TIME < SYSDATE - INTERVAL '1' HOUR 
GROUP BY BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME; 

私は、この質問を私が理解しやすいものにする助けに感謝しなければならない。すべてが期待どおりに機能しますが、パフォーマンスにはチューニングが使用される可能性があります。

2000万行

とテーブルの上に500K行

400秒とテーブルの上に1.8秒私は、Oracleが提供するいくつかの実行計画を追加したいです。パフォーマンスのチューニングに問題があります。

-- using twice self join 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name      | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | O/1/M | 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |       |  1 |  |  50 |00:00:00.84 | 99875 | 217 | 1705 |  |  |   | 
| 1 | HASH GROUP BY     |       |  1 | 6711 |  50 |00:00:00.84 | 99875 | 217 | 1705 | 1616K| 995K|   | 
|* 2 | FILTER      |       |  1 |  | 119K|00:00:00.65 | 99875 |  0 |  0 |  |  |   | 
| 3 | NESTED LOOPS OUTER   |       |  1 |  54M| 119K|00:00:00.64 | 99875 |  0 |  0 |  |  |   | 
|* 4 |  HASH JOIN OUTER    |       |  1 | 109 | 119K|00:00:00.52 | 99875 |  0 |  0 | 13M| 2093K|  1/0/0| 
| 5 |  TABLE ACCESS BY INDEX ROWID| TABLE_1_IDX    |  1 | 109 | 119K|00:00:00.14 | 85908 |  0 |  0 |  |  |   | 
|* 6 |  INDEX RANGE SCAN   | START_TIME_IDX   |  1 | 109 | 119K|00:00:00.02 |  320 |  0 |  0 |  |  |   | 
| 7 |  VIEW      |       |  1 | 1250 | 29311 |00:00:00.23 | 13967 |  0 |  0 |  |  |   | 
| 8 |  HASH GROUP BY    |       |  1 | 1250 | 29311 |00:00:00.22 | 13967 |  0 |  0 | 3008K| 1094K|  1/0/0| 
|* 9 |  FILTER     |       |  1 |  | 88627 |00:00:00.20 | 13967 |  0 |  0 |  |  |   | 
|* 10 |   TABLE ACCESS FULL  | TABLE_1     |  1 | 1250 | 88627 |00:00:00.19 | 13967 |  0 |  0 |  |  |   | 
| 11 |  VIEW      |       | 119K| 499K|  0 |00:00:00.10 |  0 |  0 |  0 |  |  |   | 
| 12 |  SORT GROUP BY    |       | 119K| 499K|  0 |00:00:00.08 |  0 |  0 |  0 | 1024 | 1024 |  1/0/0| 
|* 13 |  FILTER     |       | 119K|  |  0 |00:00:00.02 |  0 |  0 |  0 |  |  |   | 
| 14 |  TABLE ACCESS FULL  | TABLE_1     |  0 | 499K|  0 |00:00:00.01 |  0 |  0 |  0 |  |  |   | 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

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

    2 - filter([email protected]!-17<[email protected]!-16) 
    4 - access("YESTERDAY"."ZONE"="T1"."ZONE" AND "YESTERDAY"."NETWORK"="T1"."NETWORK" AND "YESTERDAY"."HOUR_OF_DAY"="T1"."HOUR_OF_DAY" 
       AND "T1"."END_TIME"=INTERNAL_FUNCTION("YESTERDAY"."END_TIME")+1 AND 
       "T1"."START_TIME"=INTERNAL_FUNCTION("YESTERDAY"."START_TIME")+1) 
    6 - access("T1"."START_TIME">[email protected]!-17 AND "T1"."START_TIME"<[email protected]!-16) 
    9 - filter([email protected]!-17<[email protected]!-16) 
    10 - filter((INTERNAL_FUNCTION("START_TIME")+1>[email protected]!-17 AND INTERNAL_FUNCTION("START_TIME")+1<[email protected]!-16)) 
    13 - filter(("YESTERDAY"."ZONE"="T1"."ZONE" AND "YESTERDAY"."NETWORK"="T1"."NETWORK" AND "YESTERDAY"."HOUR_OF_DAY"="T1"."HOUR_OF_DAY" 
       AND "T1"."END_TIME"=INTERNAL_FUNCTION("YESTERDAY"."END_TIME")+7 AND 
       "T1"."START_TIME"=INTERNAL_FUNCTION("YESTERDAY"."START_TIME")+7)) 

分析クエリを使用して別の実行計画あなたが見ることができるように、私はからクエリの利点を自己参加のstart_timeにインデックスを追加しましたが、実績はオフになっている対推定

-- using analytic query 
------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation    | Name    | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M | 
------------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |     |  1 |  |  50 |00:00:01.51 | 13967 |  |  |   | 
| 1 | HASH GROUP BY  |     |  1 | 499K|  50 |00:00:01.51 | 13967 | 98M| 7788K|   | 
|* 2 | VIEW    |     |  1 | 499K| 119K|00:00:01.15 | 13967 |  |  |   | 
| 3 | WINDOW SORT  |     |  1 | 499K| 499K|00:00:01.43 | 13967 | 66M| 2823K|  1/0/0| 
|* 4 |  FILTER   |     |  1 |  | 499K|00:00:00.16 | 13967 |  |  |   | 
| 5 |  TABLE ACCESS FULL| TABLE_1   |  1 | 499K| 499K|00:00:00.12 | 13967 |  |  |   | 
------------------------------------------------------------------------------------------------------------------------------- 

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

    2 - filter(("T1"."START_TIME">[email protected]!-INTERVAL'+17 00:00:00' DAY(2) TO SECOND(0) AND 
       "T1"."START_TIME"<[email protected]!-INTERVAL'+16 00:00:00' DAY(2) TO SECOND(0))) 
    4 - filter([email protected]!-INTERVAL'+17 00:00:00' DAY(2) TO SECOND(0)<[email protected]!-INTERVAL'+16 00:00:00' DAY(2) TO 
       SECOND(0)) 

(MT0にもう一度感謝を) 。分析クエリは、インデックスとは何も関係がないと判断するだけです。すべてのアイデア、参考点、または助けをいただければ幸いです。事前に感謝、誰もが。

+0

あなたがしようとしていることを説明するのに役立つサンプルデータを投稿できますか? 'field_6'と' field_7'の日付は時間なしであるのですか、それとも時間の成分があり、同じグループ内に複数の値がありますか? – MT0

+0

あなたは 'field_6'と' field_7'に外部結合しています - あなたは昨日と先週の結合がフィールド1,2、および3(グループ化しています)と同じ値を持っていることをどのように知っていますか? – MT0

+0

MT0、お返事ありがとうございます。より現実的なフィールド名を表示するようにクエリを修正しました。私もタイプを指定しました。ご協力いただきありがとうございます。 – OneClutteredMind

答えて

1

今日と昨日(または先週)がまったく同じ時刻の行がある場合にのみ参加する理由は不明ですが、特定の時間間隔の行が必要な場合は、すべての自己結合を削除できますそして、実行します。ただし

SELECT order_line, 
     zone, 
     network, 
     sum(
     CASE WHEN SYSDATE - INTERVAL '12' HOUR <= start_time 
      AND start_time < SYSDATE - INTERVAL '1' HOUR 
      THEN success 
      END 
     ) AS total_successes_today, 
     sum(
     CASE WHEN SYSDATE - INTERVAL '12' HOUR <= start_time 
      AND start_time < SYSDATE - INTERVAL '1' HOUR 
      THEN error 
      END 
     ) AS total_errors_today, 
     sum(
     CASE WHEN SYSDATE - INTERVAL '36' HOUR <= start_time 
      AND start_time < SYSDATE - INTERVAL '25' HOUR 
      THEN success 
      END 
     ) AS total_successes_yesterday, 
     sum(
     CASE WHEN SYSDATE - INTERVAL '180' HOUR <= start_time 
      AND start_time < SYSDATE - INTERVAL '169' HOUR 
      THEN success 
      END 
     ) AS total_successes_last_week 
FROM table_1 
WHERE ( SYSDATE - INTERVAL '12' HOUR <= start_time 
     AND start_time < SYSDATE - INTERVAL '1' HOUR) -- today 
OR  ( SYSDATE - INTERVAL '36' HOUR <= start_time 
     AND start_time < SYSDATE - INTERVAL '25' HOUR) -- yesterday = today + 24 hours 
OR  ( SYSDATE - INTERVAL '180' HOUR <= start_time 
     AND start_time < SYSDATE - INTERVAL '169' HOUR) -- last week = today + 7*24 hours 

、あなたは、あなたが分析クエリ使用することができスタート - エンド回に参加を維持したいならば:あなたが希望するかどうかを調べることができます

SELECT order_line, 
     zone, 
     network, 
     SUM(success), 
     SUM(error), 
     SUM(yesterday_success), 
     SUM(last_week_success) 
FROM (
    SELECT t.*, 
     SUM(success) 
      OVER (PARTITION BY id, 
           TO_CHAR(start_time, 'HH24:MI:SS'), 
           TO_CHAR(end_time, 'HH24:MI:SS') 
        ORDER BY start_time 
        RANGE BETWEEN INTERVAL '1' DAY PRECEDING AND INTERVAL '1' DAY PRECEDING 
       ) AS yesterday_success, 
     SUM(success) 
      OVER (PARTITION BY id, 
           TO_CHAR(start_time, 'HH24:MI:SS'), 
           TO_CHAR(end_time, 'HH24:MI:SS') 
        ORDER BY start_time 
        RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND INTERVAL '7' DAY PRECEDING 
       ) AS last_week_success 
    FROM TABLE_1 t 
) 
WHERE SYSDATE - INTERVAL '12' HOUR <= start_time 
AND start_time < SYSDATE - INTERVAL '1' HOUR 
GROUP BY 
     order_line, 
     zone, 
     network 
ORDER BY 
     order_line, 
     zone, 
     network 

をで関数ベースのインデックスを使用して速度を向上させるおよびTO_CHAR(end_time, 'HH24:MI:SS')

+0

MT0、もう一度あなたは命の恩人です。私はこれが私が探していたものだと思います。私はそれを動作させることができるかどうか見て少しあなたのサンプルで遊んでみましょう。 – OneClutteredMind

+0

MT0、あなたは男です!クエリは、私が必要とするものを正確に返します。速度がそれほど速くなくても、速度はより一貫しています。 500K行のテーブルでは、一貫した1.8秒で実行されます。自己結合には最初のクエリで10秒かかり、一度バッファリングすると0.5〜1.25秒の間にバウンスします。私は2000万行のテーブルをテストしています。私はこの例を変更して、このクエリを調整できることを望む別の業界を示す予定です。私はこれを答えにしたいと思っていましたが、私はこのフォーラムで十分な "ブラウニーポイント"がないと思います。 :) – OneClutteredMind

関連する問題