sql >> データベース >  >> RDS >> Oracle

範囲パーティションスキップチェック

    説明プランまたはテーブル定義がないと、何が起こっているのかを判断するのは非常に困難です。私の最初の推測では、yearのないローカルパーティションインデックスがあると思います 桁。これらはパーティションのCOUNT(*)に役立ちますが、1年(少なくとも10.2.0.3)をクエリするときには使用されていないようです。

    これがあなたの発見(そして回避策)を再現する小さな例です:

    SQL> CREATE TABLE DATA (
      2     YEAR NUMBER NOT NULL,
      3     ID NUMBER NOT NULL,
      4     extra CHAR(1000)
      5  ) PARTITION BY RANGE (YEAR) (
      6     PARTITION part1 VALUES LESS THAN (2010),
      7     PARTITION part2 VALUES LESS THAN (2011)
      8  );
    Table created
    
    SQL> CREATE INDEX ix_id ON DATA  (ID) LOCAL;
    Index created
    
    SQL> INSERT INTO DATA 
      2  (SELECT 2009+MOD(ROWNUM, 2), ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <=1e4);
    
    10000 rows inserted
    
    SQL> EXEC dbms_stats.gather_table_stats(USER, 'DATA', CASCADE=>TRUE);
    
    PL/SQL procedure successfully completed
    

    次に、2つの説明プランを比較します。

    SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;
    
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=197 Card=1 Bytes=4)
       1    0   SORT (AGGREGATE)
       2    1     PARTITION RANGE (SINGLE) (Cost=197 Card=5000 Bytes=20000)
       3    2       TABLE ACCESS (FULL) OF 'DATA' (TABLE) (Cost=197 Card=5000...)
    
    SQL> SELECT COUNT(*) FROM DATA PARTITION (part1);
    
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=1)
       1    0   SORT (AGGREGATE)
       2    1     PARTITION RANGE (SINGLE) (Cost=11 Card=5000)
       3    2       INDEX (FULL SCAN) OF 'IX_ID' (INDEX) (Cost=11 Card=5000)
    

    ご覧のとおり、インデックスはないです。 年を直接照会するときに使用されます。年をLOCALインデックスに追加すると、その年が使用されます。 COMPRESS 1命令を使用して、最初の列を圧縮するようにOracleに指示しました。結果のインデックスは元のインデックスとほぼ同じサイズであるため(圧縮のおかげで)、パフォーマンスに影響を与えることはありません。

    SQL> DROP INDEX ix_id;
     Index dropped
    
    SQL> CREATE INDEX ix_id ON DATA (year, ID) LOCAL COMPRESS 1;
    Index created
    
    SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;
    
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=12 Card=1 Bytes=4)
       1    0   SORT (AGGREGATE)
       2    1     PARTITION RANGE (SINGLE) (Cost=12 Card=5000 Bytes=20000)
       3    2       INDEX (RANGE SCAN) OF 'IX_ID' (INDEX) (Cost=12 Card=5000...)
    


    1. MariaDBでREPLACE()がどのように機能するか

    2. Oracle、MSSQL、MySQL、PostgreSQL間の基本的な管理の比較

    3. クライアントから送信されたリクエストは、@DateTimeFormatを使用して構文的に正しくありませんでした

    4. 並行性の問題を処理するための最良の方法