索引の理解

TimesTen Scaleoutでは、ローカル索引とグローバル索引が両方ともサポートされています。

  • ローカル索引: TimesTen Scaleoutにより、データベースのすべての要素に索引が作成されます。各要素内の索引は、その要素内の行にマップされます。表の分散キー列すべても含まれていない、索引列に対する問合せには、すべてのレプリカ・セット内の要素との通信が必要です。

  • グローバル索引: グローバル索引では、データベース内のすべての行がハッシュ分散スキームでマップされます。グローバル索引を作成すると、TimesTen Scaleoutにより、索引キー列に、ローカル索引とハッシュ分散スキームを使用してマテリアライズド・ビューが作成されます。マテリアライズド・ビューでは、指定された索引キー列値がどのレプリカ・セットにあるかを予測できるようになることで、問合せ実行が最適化されます。マテリアライズド・ビューでローカル索引を使用すると、問合せのパフォーマンスがさらに最適化されます。

    ノート:

    グローバル索引で定義された列に対するDML操作では、実行コストのオーバーヘッドが発生します。また、グローバル索引には、ローカル索引と比べると、ストレージ・コストのオーバーヘッドがあります。これらは、TimesTen Scaleoutでの、チューニングに関する主な矛盾点です。

問合せのパフォーマンスを向上させるために、次の場合にはローカル索引ではなくグローバル索引の使用を検討してください。

  • 一意索引。グローバル一意索引を使用すると、TimesTen Scaleoutで、一意制約チェックをより効率的に実行できます。「一意の索引の作成」を参照してください。

    ノート:

    分散キーが索引キーのサブセットである場合は、かわりにローカル一意索引を作成します。TimesTen Scaleoutでは、他のローカル一意索引の場合と同様に、一意性の検証のために、すべてのレプリカ・セットにアクセスするのではなく分散キー列が使用されます。

  • 問合せで頻繁に主キー列と結合される列。結合された列セットの1つ以上が主キーでも分散キーでもない場合、このような列セットにグローバル索引を作成すると、アクセスする必要があるレプリカ・セットの数が減ることで、問合せのパフォーマンスが最適化されます。「グローバル索引を使用した主キー列への結合による問合せの最適化」を参照してください。

  • 問合せで頻繁にアクセスされる非索引列を含む索引。グローバル索引では、INCLUDE句を使用して索引構造に非索引列を追加できます。問合せによっては、このような索引内の非索引列を使用することで、実表にアクセスせずに実行できます、「グローバル索引を使用した主キー列への結合による問合せの最適化」を参照してください。

  • 索引キーが表の分散キーの接頭辞である索引

ノート:

領域使用量を減らしてDMLのパフォーマンスを向上させるために、接頭辞にある列を索引キーとして使用して、索引キー内の同じ接頭辞が付いたすべてのグローバル索引を結合して単一のグローバル索引にすることをお薦めします。

同様に、次の場合にはグローバル索引ではなくローカル索引の使用を検討してください。

  • 索引キーが次の条件を満たす索引:

    • 一意でない列のみで構成されている。

    • 表の分散キーと同じである。

  • 表の分散キーが索引キーの接頭辞である索引。

グローバル索引は、次の場合にはサポートされません。

  • 複製分散スキームを使用する表

  • 参照分散スキームを使用する表であり、その表で、参照分散スキームを使用して分散キーで表が参照される場合。

『Oracle TimesTen In-Memory Database SQLリファレンス』ALTER TABLECREATE INDEXおよびCREATE TABLEを参照してください。

次の例があります。

一意の索引の作成

次の例では、既存の表に一意索引(ローカルおよびグローバル)を作成する方法と、その表に値を挿入するための問合せオプティマイザ計画を示します。

accounts表に挿入された電話番号が一意であることと、その表ですでに主キーおよびハッシュ分散キーとしてaccount_id列が使用されていることを確認する必要があるとします。

Command> DESCRIBE accounts;

Table TERRY.ACCOUNTS:
  Columns:
   *ACCOUNT_ID                      NUMBER (10) NOT NULL
    PHONE                           VARCHAR2 (16) INLINE NOT NULL
    ACCOUNT_TYPE                    CHAR (1) NOT NULL
    STATUS                          NUMBER (2) NOT NULL
    CURRENT_BALANCE                 NUMBER (10,2) NOT NULL
    PREV_BALANCE                    NUMBER (10,2) NOT NULL
    DATE_CREATED                    DATE NOT NULL
    CUST_ID                         NUMBER (10) NOT NULL
  PRIMARY KEY (ACCOUNT_ID) RANGE INDEX
  DISTRIBUTE BY HASH (ACCOUNT_ID)

1 table found.
(primary key columns are indicated with *)

ローカル一意索引を作成するときには、次に示すように、TimesTen Scaleoutで、データベースのすべてのレプリカ・セットに接続して、phone列で挿入または更新された値の一意性が検証される必要があります。

Command> CREATE UNIQUE INDEX phone_ix ON accounts(phone);
Command> INDEXES;

Indexes on table TERRY.ACCOUNTS:
  ACCOUNTS: unique range index on columns: 
    ACCOUNT_ID
  PHONE_IX: unique range index on columns: 
    PHONE
  2 indexes found.

2 indexes found on 1 table.
Command> EXPLAIN INSERT INTO accounts VALUES(?,?,?,?,?,?,?,?);

Query Optimizer Plan:

  STEP:                1
  LEVEL:               5
  OPERATION:           RowLkInsert
  TBLNAME:             ACCOUNTS
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         
  MISCELLANEOUS:       


  STEP:                2
  LEVEL:               4
  OPERATION:           GridRoute(Dist: DistHash, Kind: 1ProducerNConsumer)
  TBLNAME:             
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         
  MISCELLANEOUS:       


  STEP:                3
  LEVEL:               3
  OPERATION:           DMLScan
  TBLNAME:             
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         
  MISCELLANEOUS:       opNodeCnt=1, RowLkInsert(ACCOUNTS)


  STEP:                4
  LEVEL:               2
  OPERATION:           GridRoute(Dist: Duplicate, Kind: NProducerNConsumer)
  TBLNAME:             
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         
  MISCELLANEOUS:       


  STEP:                5
  LEVEL:               1
  OPERATION:           GlobalCheckConstraint
  TBLNAME:             ACCOUNTS
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         
  MISCELLANEOUS:       UniqueKeyInsert(idx:PHONE_IX)

そうではなくグローバル一意索引を作成する場合は、グローバル索引によって作成されるマテリアライズド・ビュー内の行の場所がphone列の値によって決まるため、TimesTen Scaleoutによるphone列値の一意性の検証がより効率的になります。グローバル索引でマテリアライズド・ビューに作成されるローカル索引により、問合せパフォーマンスが最適になります。

グローバル索引を使用した主キー列への結合による問合せの最適化

次の例では、問合せでよく主キー列に結合される列に対する問合せを、グローバル索引の使用によって最適化する方法を示します。

主キーと分散キーの両方として、customers表でcust_id列、accounts表でaccount_id列、call_records表でcall_id列を使用するとします。

Command> DESCRIBE customers;

Table TERRY.CUSTOMERS:
  Columns:
   *CUST_ID                         NUMBER (10) NOT NULL
    FIRST_NAME                      VARCHAR2 (30) INLINE NOT NULL
    LAST_NAME                       VARCHAR2 (30) INLINE NOT NULL
    ADDR1                           VARCHAR2 (64) INLINE
    ADDR2                           VARCHAR2 (64) INLINE
    ZIPCODE                         VARCHAR2 (5) INLINE
    ACCOUNT_ID                      NUMBER (10)
    MEMBER_SINCE                    DATE NOT NULL
  PRIMARY KEY (CUST_ID) RANGE INDEX
  DISTRIBUTE BY HASH (CUST_ID)

1 table found.
(primary key columns are indicated with *)
Command> DESCRIBE accounts;

Table TERRY.ACCOUNTS:
  Columns:
   *ACCOUNT_ID                      NUMBER (10) NOT NULL
    PHONE                           VARCHAR2 (16) INLINE NOT NULL
    ACCOUNT_TYPE                    CHAR (1) NOT NULL
    STATUS                          NUMBER (2) NOT NULL
    CURRENT_BALANCE                 NUMBER (10,2) NOT NULL
    PREV_BALANCE                    NUMBER (10,2) NOT NULL
    DATE_CREATED                    DATE NOT NULL
    CUST_ID                         NUMBER (10) NOT NULL
  PRIMARY KEY (ACCOUNT_ID) RANGE INDEX
  DISTRIBUTE BY HASH (ACCOUNT_ID)

1 table found.
(primary key columns are indicated with *)
Command> DESCRIBE call_records;

Table TERRY.CALL_RECORDS:
  Columns:
   *CALL_ID                         NUMBER (10) NOT NULL
    CALLER                          NUMBER (10) NOT NULL
    RECEIVER                        NUMBER (10) NOT NULL
    CALL_TIME                       TIMESTAMP (6) NOT NULL
    CODE                            NUMBER (38) NOT NULL
  PRIMARY KEY (CALL_ID) RANGE INDEX
  DISTRIBUTE BY HASH (CALL_ID)

1 table found.
(primary key columns are indicated with *)

また、次の問合せで示すように、特定のコードを使用して電話をかけたアカウントおよび顧客についてレポートする必要があるとします。

SELECT accounts.account_id, customers.cust_id, call_records.code
    FROM accounts, customers, call_records
    WHERE customers.cust_id = call_records.caller
        AND call_records.code = ?
        AND customers.account_id = accounts.account_id;

customers.cust_id列およびaccounts.account_id列がそれぞれの表の主キーである場合、それらの列に対する問合せはすでに最適化されています。ただし、customers表とcall_records表との結合を最適化するために、この例では、call_records.caller列にcustomer_calls_gixグローバル索引を作成し、call_records.code列を含めて、問合せの実行中にcall_records表にまたアクセスする必要をなくします。

CREATE GLOBAL INDEX customer_calls_gix 
    ON call_records(caller)
    INCLUDE (code)
    DISTRIBUTE BY HASH;

さらに、この例では、customers.account_id列にcustomer_account_gixグローバル索引を作成して、customers表とaccounts表との結合を最適化します。