索引の理解
TimesTen Scaleoutでは、ローカル索引とグローバル索引が両方ともサポートされています。
-
ローカル索引: TimesTen Scaleoutにより、データベースのすべての要素に索引が作成されます。各要素内の索引は、その要素内の行にマップされます。表の分散キー列すべても含まれていない、索引列に対する問合せには、すべてのレプリカ・セット内の要素との通信が必要です。
-
グローバル索引: グローバル索引では、データベース内のすべての行がハッシュ分散スキームでマップされます。グローバル索引を作成すると、TimesTen Scaleoutにより、索引キー列に、ローカル索引とハッシュ分散スキームを使用してマテリアライズド・ビューが作成されます。マテリアライズド・ビューでは、指定された索引キー列値がどのレプリカ・セットにあるかを予測できるようになることで、問合せ実行が最適化されます。マテリアライズド・ビューでローカル索引を使用すると、問合せのパフォーマンスがさらに最適化されます。
ノート:
グローバル索引で定義された列に対するDML操作では、実行コストのオーバーヘッドが発生します。また、グローバル索引には、ローカル索引と比べると、ストレージ・コストのオーバーヘッドがあります。これらは、TimesTen Scaleoutでの、チューニングに関する主な矛盾点です。
問合せのパフォーマンスを向上させるために、次の場合にはローカル索引ではなくグローバル索引の使用を検討してください。
-
一意索引。グローバル一意索引を使用すると、TimesTen Scaleoutで、一意制約チェックをより効率的に実行できます。「一意の索引の作成」を参照してください。
ノート:
分散キーが索引キーのサブセットである場合は、かわりにローカル一意索引を作成します。TimesTen Scaleoutでは、他のローカル一意索引の場合と同様に、一意性の検証のために、すべてのレプリカ・セットにアクセスするのではなく分散キー列が使用されます。
-
問合せで頻繁に主キー列と結合される列。結合された列セットの1つ以上が主キーでも分散キーでもない場合、このような列セットにグローバル索引を作成すると、アクセスする必要があるレプリカ・セットの数が減ることで、問合せのパフォーマンスが最適化されます。「グローバル索引を使用した主キー列への結合による問合せの最適化」を参照してください。
-
問合せで頻繁にアクセスされる非索引列を含む索引。グローバル索引では、
INCLUDE
句を使用して索引構造に非索引列を追加できます。問合せによっては、このような索引内の非索引列を使用することで、実表にアクセスせずに実行できます、「グローバル索引を使用した主キー列への結合による問合せの最適化」を参照してください。 -
索引キーが表の分散キーの接頭辞である索引。
ノート:
領域使用量を減らしてDMLのパフォーマンスを向上させるために、接頭辞にある列を索引キーとして使用して、索引キー内の同じ接頭辞が付いたすべてのグローバル索引を結合して単一のグローバル索引にすることをお薦めします。
同様に、次の場合にはグローバル索引ではなくローカル索引の使用を検討してください。
-
索引キーが次の条件を満たす索引:
-
一意でない列のみで構成されている。
-
表の分散キーと同じである。
-
-
表の分散キーが索引キーの接頭辞である索引。
グローバル索引は、次の場合にはサポートされません。
-
複製分散スキームを使用する表
-
参照分散スキームを使用する表であり、その表で、参照分散スキームを使用して分散キーで表が参照される場合。
『Oracle TimesTen In-Memory Database SQLリファレンス』のALTER TABLE、CREATE 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
表との結合を最適化します。