0

複合主キー (WORK_DATE、EMP_ID) の正確な昇順で Oracle 行をソートしたいと考えています。SQL Server では、クラスタ化インデックスを簡単に作成すると、魔法のように問題が解決します。一見、Oracle の ORGANIZATION INDEX (または IOT) は実行可能なソリューションを提供するように見えましたが、そうではありません。

次の DDL は、この問題を示しています。データを可能な限り現実的なものにしました。特に、行ごとにサイズが異なるかなり大きな VARCHAR フィールドがあるという事実です (おそらく、Oracle が行のストレージを並べ替えるのを思いとどまらせます)。

アドホック ユーザーが「ORDER BY 1, 2」を追加しなくても、クエリ #2 の出力と同じように行が格納されるようにするソリューションを探しています。ORDER BY ステートメントを追加するのを忘れて、最新の WORK_DATE を取得していると考えて、一番下にCTRL+を追加する不器用なユーザーがいます。END埋め込みの ORDER BY ステートメントを含むビューを作成して、これを解決したくありません。DDL ステートメントの修正を提案できますか? おそらく、「ORGANIZATION INDEX」キーワードの後に​​追加の句またはパラメーターが必要ですか? ご協力ありがとうございます。

CREATE TABLE EMPLOYEE_HOURS (
      WORK_DATE       DATE          NOT NULL 
    , EMP_ID          VARCHAR2(15)  NOT NULL
    , HOURS_WORKED    NUMBER(22)    NOT NULL
    , WORK_COMMENT    VARCHAR2(150) NOT NULL    
    , ROW_INSERT_DATE TIMESTAMP DEFAULT SYSTIMESTAMP
    , CONSTRAINT EMPLOYEE_HOURS_PK PRIMARY KEY (WORK_DATE, EMP_ID)
) ORGANIZATION INDEX;


/* create test data that mimics my real world data */
BEGIN
    FOR loop_id IN 1 .. 10000
    LOOP

    INSERT INTO EMPLOYEE_HOURS VALUES (
          TRUNC(SYSDATE) - TRUNC(dbms_random.value(-150, 150))
        , UPPER(dbms_random.string('A', 3)) 
                       || TRUNC(dbms_random.value(1000, 999999)) 
        , dbms_random.value(0.5, 18.5)
        , regexp_replace(SUBSTR(LOWER(dbms_random.string('A', 100))
                            , 1
                            , TRUNC(dbms_random.value(4, 100))), '(.....)', '\1 ')
        , SYSTIMESTAMP);
    COMMIT WORK; 
    END LOOP;
END;


/* compare these queries and notice that the sort order in the first query does not
   conform to the expected order of the IOT composite index (WORK_DATE, EMP_ID) */

    /* Query #1 */
SELECT * FROM EMPLOYEE_HOURS;

    /* Query #2 */
SELECT * FROM EMPLOYEE_HOURS ORDER BY 1, 2;
4

1 に答える 1

1

IOT は、連続する行が連続するブロックに格納されることを保証しません。また、行がソートされた順序で取得されることを保証するものではありません。

Oracle で行の格納方法を制御するのに最も近いのは、クラスター化されたテーブルです。

さて、ソリューションにはいくつかの基本的な問題があると思います:

  1. 順序付けられた結果を取得するにはインデックスが最適であると主張していますが、それは完全に正しいとは言えません。インデックス スキャンでは 1 回の IO アクセスが必要ですが、フル スキャンでは 1 回の IO で複数のブロックをフェッチできます。したがって、インデックスを使用して 10 ブロックのテーブルを取得すると、10 IO になりますがmulti_block_read_count = 32、FTS とハッシュ ソートを使用した同じクエリでは、CPU が少し多く必要になりますが、IO は 1 回だけです。それについて考えてください。

  2. order by を実行する以外に、ソートされた結果を保証する方法はありません。おそらく、テーブルの上にビューを宣言し、そこでソートを実行する必要があります。

于 2014-01-08T07:13:03.227 に答える