例えば、Name プロパティが文字列として定義されていると、そのプロパティの既定は SQLUPPER 照合になります。Name に対するインデックスを定義すると、そのプロパティの照合が既定で取得され、そのインデックスも SQLUPPER を使用して定義されます。プロパティの照合とインデックスの照合が一致します。
Index IndexName On PropertyName As CollationName;
以下はその説明です。
以下はその例です。
Index NameIDX On Name As Exact;
異なるプロパティは、異なる照合タイプを持つことができます。例えば、以下の例では、F1 プロパティは SQLUPPER 照合を使用する一方で、F2 は EXACT 照合を使用します。
Index Index1 On (F1 As SQLUPPER, F2 As EXACT);
推奨される照合タイプのリストについては、"InterSystems SQL の使用法" の “照合” の章にある “照合タイプ” のセクションを参照してください。
Note:
Unique、PrimaryKey、または IdKey として指定されたインデックスには、インデックス照合を指定できません。このインデックスの照合は、プロパティの照合から取得されます。
インデックスでの Unique、PrimaryKey、IdKey キーワードの使用
SQL では普通のことですが、InterSystems IRIS では一意キーと主キーの概念をサポートしています。また、InterSystems IRIS には IdKey を定義する機能もあります。IdKey とは、クラスのインスタンス (テーブルの行) に対して一意のレコード ID となるものです。これらの機能は、以下に示す Unique、PrimaryKey、IdKey の各キーワードを使用して実装されます。
-
Unique — インデックスのプロパティ・リストに含まれているプロパティに対する UNIQUE 制約を定義します。そのため、このプロパティ (フィールド) で一意のデータ値のみがインデックス化できるようになります。一意性は、プロパティの照合に基づいて判断されます。例えば、プロパティの照合が EXACT の場合、大文字/小文字の異なる値は一意になります。プロパティの照合が SQLUPPER の場合は、大文字/小文字が異なる値は一意にはなりません。ただし、未定義のプロパティに対してインデックスの一意性はチェックされないことに注意してください。SQL 標準に従い、未定義のプロパティは常に一意として扱われます。
-
PrimaryKey — インデックスのプロパティ・リストに含まれているプロパティに対する PRIMARY KEY 制約を定義します。
-
IdKey — 一意の制約を定義し、インスタンス (行) の一意の ID を定義するために使用するプロパティを指定します。IdKey は、常に EXACT 照合を持ちます (データ型が文字列でも同じ照合になります)。
このようなキーワードの構文を表示すると、以下の例のようになります。
Class MyApp.SampleTable Extends %Persistent [DdlAllowed]
{
Property Prop1 As %String;
Property Prop2 As %String;
Property Prop3 As %String;
Index Prop1IDX on Prop1 [ Unique ];
Index Prop2IDX on Prop2 [ PrimaryKey ];
Index Prop3IDX on Prop3 [ IdKey ];
}
Note:
IdKey、PrimaryKey、Unique の各キーワードは、標準インデックスで使用する場合にのみ有効です。ビットマップ・インデックスやビットスライス・インデックスで使用することはできません。
また、以下のように、IdKey と PrimaryKey の両方のキーワードを組み合わせて指定する構文も有効です。
Index IDPKIDX on Prop4 [ IdKey, PrimaryKey ];
この構文では、IDPKIDX インデックスがクラス (テーブル) の IdKey であり、かつその主キーであることを指定します。これらのキーワードを上記以外の形で組み合わせた場合は、すべて冗長になります。
インデックスがこれらのキーワードのいずれかを使用して定義されていると、そのインデックスに関連付けられたプロパティに特定の値が指定されているクラスのインスタンスを開くことができるメソッドがあります。詳細は、“インデックス・キーによるインスタンスのオープン” のセクションを参照してください。
IdKey キーワードの詳細は、"クラス定義リファレンス" の "IdKey" のページを参照してください。PrimaryKey キーワードの詳細は、"クラス定義リファレンス" の "PrimaryKey" のページを参照してください。Unique キーワードの詳細は、"クラス定義リファレンス" の "Unique" のページを参照してください。
インデックスを使用したデータの保存
インデックスの Data キーワードを使用して、1 つ以上のデータ値のコピーをインデックスに保存するように指定できます。
Class Sample.Person Extends %Persistent [DdlAllowed]
{
Property Name As %String;
Property SSN As %String(MAXLEN=20);
Index NameIDX On Name [Data = Name];
}
この場合、インデックス NameIDX には、さまざまな Name 値の照合値 (大文字) によって添え字が付けられます。Name の実際の (照合されていない) 値のコピーは、インデックスに保存されています。これらのコピーは、SQL を使用して Sample.Person テーブルが変更された場合や、オブジェクトを使用して対応する Sample.Person クラスまたはそのインスタンスが変更された場合も維持されます。
選択 (多数の行から数行を選ぶ) や抽出 (多数の列から数列を返す) を頻繁に実行する場合、インデックスにデータのコピーを維持する機能は大変便利です。
例えば、Sample.Person テーブルに対する以下のクエリがあります。
SELECT Name FROM Sample.Person ORDER BY Name
SQL エンジンは、テーブルのマスタ・データを読まずに、NameIDX を読むだけですべての要求を満たすことができます。
Note:
ビットマップ・インデックスでは、値を保存できません。
NULL のインデックス付け
インデックスが付けられたフィールドのデータに NULL (データが存在しない) が含まれている場合、対応するインデックスでは、このフィールドがインデックス NULL 標識を使用して表されます。既定では、インデックス NULL 標識の値は -1E14 です。インデックス NULL 標識を使用することで、NULL 以外のすべての値の前に NULL 値を照合するようになります。INDEXNULLMARKER プロパティ・パラメータを使用することで、特定のフィールドについてインデックス NULL 標識の値を変更できます。
コレクションのインデックス作成
プロパティにインデックスが付けられる場合、インデックスに配置される値は照合プロパティ値全体です。コレクションの場合は、プロパティ名に (ELEMENTS) または (KEYS) を追加することで、コレクションの要素値とキー値に対応するインデックス・プロパティを定義することができます。(ELEMENTS) と (KEYS) を使用すると、1 つのプロパティ値から複数の値を生成して、それらの各サブ値にインデックスを作成するように指定できます。プロパティがコレクションの場合、ELEMENTS トークンはコレクションの要素を値で参照し、KEYS トークンは同様の要素を位置で参照します。1 つのインデックス定義に ELEMENTS と KEYS の両方が存在する場合、インデックスのキー値には、キーとそれに関連付けられた要素の値が保存されます。
例えば、Sample.Person クラスの FavoriteColors プロパティに基づくインデックスがあるとします。このプロパティのコレクション内の項目のインデックスのうち、最も単純な形式は以下のいずれかになります。
INDEX fcIDX1 ON (FavoriteColors(ELEMENTS));
または
INDEX fcIDX2 ON (FavoriteColors(KEYS));
FavoriteColors(ELEMENTS) は FavoriteColors プロパティの要素、FavoriteColors(KEYS) は FavoriteColors プロパティのキーです。一般的な形式は、propertyName(ELEMENTS) または propertyName(KEYS) です。ここで、そのコレクションの内容は、いくつかのデータ型の List Of または Array Of として定義されたプロパティに含まれる一連の要素です。コレクションについては、"クラスの定義と使用" の “コレクションを使用した作業” の章を参照してください。
リテラル・プロパティ ("クラスの定義と使用" の “リテラル・プロパティの定義と使用” の章を参照) にインデックスを作成するには、propertyNameBuildValueArray() メソッドでインデックス値配列を作成します (以下のセクションを参照)。固有のコレクションと同様、(ELEMENTS) 構文および (KEYS) 構文は、インデックス値配列と併用可能です。
プロパティ・コレクションが配列として投影される場合、インデックスがコレクション・テーブルに投影されるためには以下の制限に従う必要があります。インデックスには (KEYS) を含める必要があります。インデックスは、コレクション自体とオブジェクトの ID 値以外のプロパティを参照することはできません。投影されるインデックスが、インデックスに格納される DATA も定義する場合、格納されるデータ・プロパティも、そのコレクションと ID に制限される必要があります。そうしないと、インデックスは投影されません。この制限は、配列として投影されるコレクション・プロパティ上のインデックスに適用されます。リストとして投影されるコレクション上のインデックスには適用されません。詳細は、"クラスの定義と使用" の “コレクション・プロパティの SQL プロジェクションの制御” を参照してください。
コレクションの要素値またはキー値に対応するインデックスは、インデックスを使用したデータの保存やインデックス固有の照合など、標準インデックスのすべての機能を持つこともできます。
InterSystems SQL は、FOR SOME %ELEMENT 述語を指定することによって、コレクション・インデックスを使用することができます。
(ELEMENTS) および (KEYS) を使用したデータ型プロパティのインデックス作成
データ型プロパティのインデックスを作成するために、BuildValueArray() メソッドを使用してインデックス値配列を作成することもできます。このメソッドは、プロパティ値をキーおよび要素の配列に構文解析します。このメソッドは、それを行うために、関連付けられているプロパティの値から派生した要素値のコレクションを作成します。このメソッドは、既存のコレクション・プロパティでは機能しません。
BuildValueArray() を使用してインデックス値配列を作成する場合、その構造はインデックス作成に適しています。
BuildValueArray() メソッドには propertyNameBuildValueArray() という名前があり、そのシグニチャは以下のようになります。
ClassMethod propertynameBuildValueArray(value, ByRef valueArray As %Library.String) As %Status
以下はその説明です。
配列コレクションのインデックス作成
配列コレクションのプロパティにインデックスを指定するには、そのインデックス定義にキーを追加する必要があります。例えば以下のようにします。
Class MyApp.Branch Extends %Persistent [ DdlAllowed ]
{
Property Name As %String;
Property Employees As Array Of MyApp.Employee;
Index EmpIndex On (Employees(KEYS), Employees(ELEMENTS));
}
これらのキーは、配列要素の子テーブルにある行の RowID を特定します。このキーがないと、親テーブルから子テーブルにインデックスが投影されません。この投影が発生しないことから、親テーブルへの INSERT 操作が失敗します。
埋め込みオブジェクト (%SerialObject) のプロパティのインデックス作成
埋め込みオブジェクト内のプロパティにインデックスを作成するには、その埋め込みオブジェクトを参照する永続クラスでインデックスを作成します。次の例で示しているように、プロパティ名に、テーブル (%Persistent クラス) 内の参照フィールドの名前および埋め込みオブジェクト (%SerialObject) 内のプロパティを指定する必要があります。
Class Sample.Person Extends (%Persistent) [ DdlAllowed ]
{ Property Name As %String(MAXLEN=50);
Property Home As Sample.Address;
Index StateInx On Home.State;
}
ここでは、Home は、State プロパティを含む埋め込みオブジェクト Sample.Address を参照する Sample.Person 内のプロパティです。以下に例を示します。
Class Sample.Address Extends (%SerialObject)
{ Property Street As %String;
Property City As %String;
Property State As %String;
Property PostalCode As %String;
}
永続クラスのプロパティ参照に関連付けられている埋め込みオブジェクトのインスタンス内のデータ値のみにインデックスが作成されます。%SerialObject プロパティにインデックスを直接作成することはできません。%Library.SerialObject の SqlCategory (および SqlCategory を明示的に定義していない %SerialObject のすべてのサブクラス) は STRING です。
埋め込みオブジェクトのプロパティで、SQL 文 CREATE INDEX を使用してインデックスを定義することもできます。以下に例を示します。
CREATE INDEX StateIdx ON TABLE Sample.Person (Home_State)
詳細は、"シリアル・オブジェクトの概要" と "埋め込みオブジェクト (%SerialObject)" を参照してください。
ビットマップ・インデックス
ビットマップ・インデックスは特殊なタイプのインデックスで、指定したインデックス付きのデータ値に対応する一連の ID 値を表す一連のビット文字列を使用します。
ビットマップ・インデックスには以下のような重要な特長があります。
-
ビットマップは高圧縮されています。つまり、ビットマップ・インデックスは標準インデックスに比べてサイズをはるかに小さくすることができるので、ディスクおよびキャッシュの使用量を大幅に削減できます。
-
ビットマップ演算は、トランザクション処理に最適化されています。テーブルでビットマップ・インデックスを使用すると、標準インデックスを使用する場合に比べ、パフォーマンスが低下しません。
-
ビットマップでの論理演算 (カウント、AND、OR) を使用すると、パフォーマンスが向上します。
-
SQL エンジンは、ビットマップ・インデックスを駆使する、特別な最適化機能を備えています。
ビットマップ・インデックスの作成は、テーブルに固有の ID フィールドの性質によって異なります。
-
テーブルの ID フィールドが正の整数値の単一フィールドとして定義されていると、この ID フィールドを使用してフィールドにビットマップ・インデックスを定義できます。このタイプのテーブルでは、システムによって割り当てられた一意の正整数 ID が使用されるか、または IdKey を使用してカスタム ID 値が定義されます。このとき、IdKey は、%Integer タイプで MINVAL が 0 より大きい単一のプロパティか、%Numeric タイプで SCALE が 0 で MINVAL が 0 より大きい単一のプロパティに基づきます。
-
テーブルの ID フィールドが正の整数値の単一フィールドとして定義されていない場合 (子テーブルなど)、正の整数をとる %BID (ビットマップ ID) フィールドを定義できます。%BID フィールドはサロゲート ID フィールドとして機能します。これによって、このテーブルのフィールドにビットマップ・インデックスを作成できます。
ビットマップ・インデックスは、以下の制限事項に従って標準インデックスと同様に機能します。インデックス値は照合されており、複数のフィールドの結合に対しインデックスを作成できます。
この章では、ビットマップ・インデックスに関連する以下の項目について説明します。
ビットマップ・インデックス演算
ビットマップ・インデックスは以下のように動作します。多数の列を持つ Person テーブルがあるとします。
Person テーブル
このテーブルの各行には、システムにより RowID 番号 (増加する整数値) が割り当てられます。ビットマップ・インデックスは、一連のビット文字列 (1 または 0 を含む文字列) を使用します。ビット文字列では、ビットの順序の位置がインデックス付きテーブルの RowID に対応します。上記のテーブルで State が “NY” である場合を例にとると、ビット文字列の “NY” を含む行に対応する各位置には 1 が、その他の位置には 0 が入ります。
例えば、State のビットマップ・インデックスは以下のとおりです。
State ビットマップ・インデックス
また、Age は以下のようになります。
Age ビットマップ・インデックス
Note:
ここで示す Age フィールドは、通常のデータ・フィールドにすることも、値を確実に派生できるフィールド (Calculated および SQLComputed) にすることもできます。
通常の演算にビットマップ・インデックスを使用する方法とは別に、SQL エンジンは、複数インデックスの結合を使用した特別なセットベースの演算を、ビットマップ・インデックスを使用して効率的に実行できます。例えば、ニューヨークに住む 24 歳以上に当てはまる Person のすべてのインスタンスを得るために、SQL エンジンは Age と State の論理 AND を実行します。
複数のインデックスの使用
結果として得られたビットマップには、検索基準に当てはまるすべての行のセットが含まれます。SQL エンジンは、これを使用して行からデータを返します。
SQL エンジンは、ビットマップ・インデックスを以下の演算に使用できます。
DDL を使用したビットマップ・インデックスの定義
テーブルの定義に DDL 文を使用している場合、以下の DDL コマンドを使用して、正整数 ID を持つテーブルのビットマップ・インデックスを作成および削除することもできます。
これは、CREATE INDEX 文に BITMAP キーワードを追加する必要がある点以外は、標準インデックスの生成とまったく同じです。
CREATE BITMAP INDEX RegionIDX ON TABLE MyApp.SalesPerson (Region)
クラス定義を使用した IdKey ビットマップ・インデックスの定義
テーブルの ID が値 (一意の正の整数に制限されている値) のフィールドの場合、標準インデックスの作成と同様に、新規インデックス・ウィザードを使用するか、クラス定義のテキストを編集することで、ビットマップ・インデックス定義をクラス定義に追加できます。ただし、ビットマップ・インデックスの場合は、インデックスの Type を “bitmap” に指定する必要があります。
Class MyApp.SalesPerson Extends %Persistent [DdlAllowed]
{
Property Name As %String;
Property Region As %Integer;
Index RegionIDX On Region [Type = bitmap];
}
クラス定義を使用した %BID ビットマップ・インデックスの定義
テーブルの ID が正整数に制限されていない場合、%BID フィールドを作成して、これをビットマップ・インデックス定義の作成に使用できます。このオプションは、特定のテーブルに、その ID フィールドのデータ型にかかわらず使用でき、複数のフィールド (子テーブルを含む) で構成される IDKEY の場合でも使用可能です。%BID ビットマップは、既定の構造テーブルと %Storage.SQL テーブルのいずれかのデータ・ストレージ・タイプに作成できます。この機能は、"あらゆるテーブルのビットマップ" (BAT) と呼ばれます。
こういったテーブルでビットマップ・インデックスを使用できるようにするには以下の手順に従います。
-
%BID フィールドを定義するか、既存のフィールドを %BID フィールドとして特定します。このフィールドのデータ型は、一意の正整数値に制限する必要があります。例えば、このテーブルの IDKey は、値が正整数に制限されていない 2 つのフィールドの複合です。これにより、データ型 (%Counter) が正整数である MyBID フィールドが %BID フィールドの候補となります。
Class MyTable Extends %Persistent [ DdlAllowed ]
{
Property IdField1 As %Integer;
Property IdField2 As %Integer;
Property MyBID As %Counter; /* %BID Field */
Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ];
}
-
SQL コンパイラに対して %BID フィールドを特定する BIDField クラス・パラメータを定義します。その値を、%BID フィールドの SQLFieldName に設定します。例えば以下のようにします。
Class MyTable Extends %Persistent [ DdlAllowed ]
{
Parameter BIDField = "MyBID"; /* BIDField Class Parameter */
Property IdField1 As %Integer;
Property IdField2 As %Integer;
Property MyBID As %Counter;
Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ];
}
-
BATKey インデックスを定義します。このインデックスは、SQL クエリ・プロセッサのマスタ・マップとデータ・マップとして機能します。多くの場合、%BID フィールドは、BATKey インデックスの 1 番目の添え字です。これにより、このマップ・データには、IDKEY フィールドと、最高速のアクセスを必要とするあらゆる補足プロパティを追加できます。%BID フィールドにインデックスを設定する必要があります。例えば以下のようにします。
Class MyTable Extends %Persistent [ DdlAllowed ]
{
Parameter BIDField = "MyBID";
Property IdField1 As %Integer;
Property IdField2 As %Integer;
Property MyBID As %Counter;
Index MyBATKey On MyBID [ Type = key, Unique ]; /* BATKey Index */
Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ];
}
-
SQL コンパイラに対して BATKey インデックスを特定する BATKey クラス・パラメータを定義します。その値を、BATKey インデックスの SQLFieldName に設定します。例えば以下のようにします。
Class MyTable Extends %Persistent [ DdlAllowed ]
{
Parameter BIDField = "MyBID";
Parameter BATKey = "MyBATKey"; /* BATKey Class Parameter */
Property IdField1 As %Integer;
Property IdField2 As %Integer;
Property MyBID As %Counter;
Index MyBATKey On MyBID [ Type = key, Unique ];
Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ];
}
-
%BID ロケータ・インデックスを定義するか、既存のインデックスを %BID ロケータ・インデックスとして特定します。このインデックスによって、%BID インデックスがテーブルの IDKey フィールドに関連付けられます。例えば以下のようにします。
Class MyTable Extends %Persistent [ DdlAllowed ]
{
Parameter BIDField = "MyBID";
Parameter BATKey = "MyBATKey";
Property IdField1 As %Integer;
Property IdField2 As %Integer;
Property MyBID As %Counter;
Index MyBATKey On MyBID [ Type = key, Unique ];
Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ];
Index BIDLocIdx On (IDfield1, IDfield2, MyBID) [ Unique ]; /* %BID Locator Index */
}
これで、このテーブルではビットマップ・インデックスがサポートされるようになります。必要に応じて、標準構文を使用してビットマップ・インデックスを定義できます。例えば、Index RegionIDX On Region [Type = bitmap]; と定義します。
このように作成したテーブルではビットスライス・インデックスもサポートされます。標準構文を使用してビットスライス・インデックスを定義することもできます。
ビットマップ・エクステント・インデックスの生成
ビットマップ・インデックスはビットマップ・エクステント・インデックスが必要です。1 つ以上のビットマップ・インデックスが定義されている場合、永続クラスを定義するとビットマップ・エクステント・インデックスのみが生成されます。したがって、ビットマップ・インデックスを含む永続クラスをコンパイルする場合、そのクラスに対するビットマップ・エクステント・インデックスが定義されていないと、クラス・コンパイラはビットマップ・エクステント・インデックスを生成します。CREATE TABLE DDL 文を使用して定義したテーブルでは、自動的にビットマップ・エクステント・インデックスが生成されます。
永続クラス定義からすべてのビットマップ・インデックスを削除すると、ビットマップ・エクステント・インデックスが自動的に削除されます。ただし、ビットマップ・エクステント・インデックスの名前を変更 (CREATE BITMAPEXTENT INDEX コマンドを使用するなど) してビットマップ・インデックスを削除しても、ビットマップ・エクステント・インデックスは削除されません。
あるクラスのインデックスを作成する際、明示的にビットマップ・エクステント・インデックスを構築した場合、またはビットマップ・インデックスを作成していて、ビットマップ・エクステント・インデックスが空である場合に、ビットマップ・エクステント・インデックスが作成されます。
クラスは、プライマリ・スーパークラスから、定義済みまたは生成されたビットマップ・エクステント・インデックスを継承します (存在する場合)。ビットマップ・エクステント・インデックスは、type = bitmap、extent = true として定義されます。つまり、プライマリ・スーパークラスから継承されたビットマップ・エクステント・インデックスは、ビットマップ・インデックスと見なされ、サブクラスでのビットマップ・エクステント・インデックスの生成をトリガします (そのサブクラスで、ビットマップ・エクステント・インデックスが明示的に定義されていない場合)。
InterSystems IRIS では、将来の可能性を考慮してスーパークラスでビットマップ・エクステント・インデックスは生成されません。つまり、InterSystems IRIS では、type = bitmap であるインデックスが存在しない限り、永続クラスでビットマップ・エクステント・インデックスが生成されることはありません。将来一部のサブクラスで type = bitmap のインデックスが導入されるかもしれないという推定だけでは不十分です。
Note:
運用システム (ユーザが特定のクラスを頻繁に使用し、そのクラスをコンパイルし、続いてビットマップ・インデックス構造を作成しているような環境) でクラスにビットマップ・インデックスを追加するプロセスでは、特別な注意が必要です。そのようなシステムでは、ビットマップ・エクステント・インデックスは、コンパイルの完了とインデックスの作成手順の中間で生成される可能性があります。これにより、インデックス作成手順では、ビットマップ・エクステント・インデックスが暗黙的に作成されず、ビットマップ・エクステント・インデックスの処理が部分的に完了することがあります。
インデックス・タイプの選択
以下は、ビットマップ・インデックスと標準インデックスのどちらを選択するべきかを判断するための指針です。一般的には、次のどの種類のキーおよび参照にインデックスを作成する場合でも標準インデックスを使用します。
-
主キー
-
外部キー
-
一意のキー
-
リレーションシップ
-
単純オブジェクト参照
上記以外のキーまたは参照の場合、一般的にはビットマップ・インデックスの使用をお勧めします (システムによって割り当てられた数値 ID 番号をテーブルで使用していることが前提となります)。
その他の要素
-
通常、複数のプロパティに対するビットマップ・インデックスよりも、プロパティごとに個別のビットマップ・インデックスの方がパフォーマンスが高くなります。これは、SQL エンジンは AND 演算と OR 演算を使用して個別のビットマップ・インデックスを効率的に結合できるためです。
-
プロパティ (または、まとめてインデックスを作成する必要がある複数のプロパティ) の個別値 (または値の組み合わせ) が 10,000 ~ 20,000 個を超える場合は、標準インデックスの使用を検討してください。しかし、これらの値が不均一に分散されているために多数の行に対する値の数が非常に少ない場合は、ビットマップ・インデックスを使用した方が有利です。常に、インデックスによる要求の全体量が少しでも少なくなる方法を使用します。
ビットマップ・インデックスに関する制限事項
すべてのビットマップ・インデックスに、以下のような制限事項があります。
-
UNIQUE 列にビットマップ・インデックスを定義することはできません。
-
ビットマップ・インデックスには、値を保存できません。
-
ID フィールドの SqlCategory が INTEGER、DATE、POSIXTIME、または NUMERIC (scale=0) である場合を除き、フィールドにビットマップ・インデックスを定義することはできません。
-
格納しているレコード数が 1,000,000 個を超えるテーブルでは、一意の値の数が 10,000 個を超えたときに、標準インデックスよりもビットマップ・インデックスの方が効率が低下します。そのため、巨大なテーブルについては、10,000 個を超える一意の値が含まれている (またはその可能性のある) フィールドに対してビットマップ・インデックスを使用しないようにしてください。また、テーブルのサイズにかかわらず、20,000 個を超える一意の値が含まれている可能性のあるフィールドにはビットマップ・インデックスを使用しないでください。これらは一般的な概数であり、正確な数ではありません。
以下のようなテーブルでビットマップ・インデックスを使用するには、%BID プロパティを作成する必要があります。
$SYSTEM.SQL.Util.SetOption()Opens in a new tab メソッド SET status=$SYSTEM.SQL.Util.SetOption("BitmapFriendlyCheck",1,.oldval) を使用すると、この制限をコンパイル時にチェックし、定義されたビットマップ・インデックスが %Storage.SQL クラス内で許可されるかどうかを判断するようにシステム全体用の構成パラメータを設定できます。このチェックは、%Storage.SQL を使用するクラスにのみ適用されます。既定値は 0 です。$SYSTEM.SQL.Util.GetOption("BitmapFriendlyCheck")Opens in a new tab を使用すると、このオプションの現在の構成を判断できます。
アプリケーション・ロジックの制限事項
ビットマップ構造は、ビット文字列の配列で表現できます。この配列の各要素が固定のビット数による 1 つの「チャンク」を表しています。未定義はすべてのビットが 0 のチャンクと同等であるため、配列はスパースになることがあります。すべてのビットが 0 のチャンクを表す配列要素は、存在している必要は一切ありません。このため、アプリケーション・ロジックでは、0 値のビットの $BITCOUNT(str,0) カウントに依存しないようにする必要があります。
ビット文字列は内部フォーマットを含んでいるため、アプリケーション・ロジックでは、ビット文字列の物理長に依存することや、同じビット値を持つ 2 のビット文字列の等価性に依存することは絶対に避けてください。ロールバック操作後、ビット文字列はトランザクション前のビット値にリストアされます。ただし、内部フォーマットのために、ロールバックされたビット文字列はトランザクション前のビット文字列と等しくならないことや、同じ物理長にならないことがあります。
ビットマップ・インデックスの維持
揮発性のテーブル (多数の INSERT 操作および DELETE 操作が実行されるもの) では、ビットマップ・インデックス用のストレージは徐々に効率が低下する可能性があります。ビットマップ・インデックスを維持するには、%SYS.Maint.BitmapOpens in a new tab ユーティリティ・メソッドを実行してビットマップ・インデックスを圧縮し、それらを最適な効率が得られるように復元します。1 つのクラスを対象にビットマップ・インデックスを圧縮するには OneClass()Opens in a new tab メソッド、ネームスペース全体でビットマップ・インデックスを圧縮するには Namespace()Opens in a new tab メソッドをそれぞれ使用できます。これらの維持メソッドは、実働システム上で実行できます。
%SYS.Maint.BitmapOpens in a new tab ユーティリティ・メソッドを実行した結果は、このメソッドを呼び出したプロセスに書き込まれます。これらの結果は、クラス %SYS.Maint.BitmapResultsOpens in a new tab にも書き込まれます。
ビットマップ・チャンクの SQL 操作
InterSystems SQL には、ビットマップ・インデックスを直接操作するための以下の拡張機能が用意されています。
-
%CHUNK 関数
-
%BITPOS 関数
-
%BITMAP 集約関数
-
%BITMAPCHUNK 集約関数
-
%SETINCHUNK 述語条件
これらの拡張機能はすべて、ビットマップ表現に関する InterSystems SQL の規約に従い、正の整数のセットを一連のビットマップ・チャンク (それぞれ最大 64,000 個の整数) として表します。
これらの拡張機能により、クエリ内でも埋め込み SQL でも、特定の条件やフィルタをより簡単かつ効率的に操作することができます。埋め込み SQL では、これらの拡張機能によって、単一チャンク・レベルでは特に、ビットマップのシンプルな入力と出力が実現します。これらの拡張機能では、%BITMAP() および %SQL.Bitmap クラスによって処理される、完全なビットマップの処理がサポートされています。また、外部キー値、親による子テーブルの参照、関連付けのどちらか一方の列など、非 RowID 値のビットマップ処理も可能です。
例えば、指定したチャンクのビットマップを出力するには、以下のように入力します。
SELECT %BITMAPCHUNK(Home_Zip) FROM Sample.Person
WHERE %CHUNK(Home_Zip)=2
テーブル全体のチャンクをすべて出力するには、以下のように入力します。
SELECT %CHUNK(Home_Zip),%BITMAPCHUNK(Home_Zip) FROM Sample.Person
GROUP BY %CHUNK(Home_Zip) ORDER BY 1
%CHUNK 関数
%CHUNK(f) は、ビットマップ・インデックスが付いたフィールドの f 値に対するチャンク割り当てを返します。これは、f\64000+1 として計算されます。ビットマップ・インデックスが付いたフィールドでないフィールドまたは値 f の %CHUNK(f) は、常に 1 を返します。
%BITPOS 関数
%BITPOS(f) は、ビットマップ・インデックスが付いたフィールドの f 値に割り当てられた、そのチャンク内のビット位置を返します。これは、f#64000+1 として計算されます。ビットマップ・インデックスが付いたフィールドでないフィールドまたは値 f の %BITPOS(f) は、その整数値より 1 大きい値を返します。文字列の整数値は 0 です。
%BITMAP 集約関数
集約関数 %BITMAP(f) は、多数の f 値を 1 つの %SQL.Bitmap オブジェクトに結合します。ここでは、結果セット内のそれぞれの値 f について、適切なチャンク内の f に対応するビットが 1 に設定されます。 前述のすべての f は通常、正の整数のフィールド (または式) です。一般的には RowID ですが、必ず RowID というわけではありません。
%BITMAPCHUNK 集約関数
集約関数 %BITMAPCHUNK(f) は、フィールド f の多くの値を 64,000 ビットの InterSystems SQL 標準ビットマップ文字列に結合します。ここでは、セット内のそれぞれの値 f について、ビット f#64000+1=%BITPOS(f) が 1 に設定されます。%CHUNK(f) の値に関係なく、結果内でビットが設定されます。%BITMAPCHUNK() は、空のセットについては NULL を生成し、他の集約関数と同様に、入力に含まれる NULL 値は無視します。
%SETINCHUNK 述語条件
条件 (f %SETINCHUNK bm) が true になるのは、($BIT(bm,%BITPOS(f))=1) の場合のみです。bm は、ビットマップ式文字列 (例 : 入力ホスト変数 :bm)、%BITMAPCHUNK() 集約関数の結果などです。%CHUNK(f) の値に関係なく、<bm> ビットがチェックされます。<bm> がビットマップでない場合、または NULL である場合、この条件は FALSE を返します。 (f %SETINCHUNK NULL) は FALSE になります (UNKNOWN ではありません)。
ビットスライス・インデックス
ビットスライス・インデックスは、数値データ・フィールドを特定の数値演算に使用する場合に、そのフィールドに使用します。ビットスライス・インデックスは、各数値データをバイナリのビット文字列として表します。ビットスライス・インデックスは、ビットマップ・インデックスのようにブーリアン・フラグを使用して数値データのインデックスを作成するのではなく、バイナリの各数値を表し、バイナリ値の桁ごとにビットマップを作成してそのバイナリの桁が 1 である行を記録します。これは、以下の演算のパフォーマンスを大幅に向上させることができる非常に特殊なタイプのインデックスです。
-
SUM、COUNT、または AVG 集約計算(ビットスライス・インデックスは COUNT(*) 計算には使用できません)。ビットスライス・インデックスは、その他の集約関数には使用されません。
-
TOP n ... で指定されたフィールド。ORDER BY field 演算。
-
WHERE field > n や WHERE field BETWEEN lownum AND highnum など、範囲条件演算で指定されたフィールド。
SQL オプティマイザは、定義されたビットスライス・インデックスを使用するべきかどうかを決定します。一般に、オプティマイザは、かなりの数 (数千) の行が処理される場合にのみ、ビットスライス・インデックスを使用します。
文字列データ・フィールドについてビットスライス・インデックスを作成できますが、ビットスライス・インデックスは、これらのデータ値をキャノニック形式の数値として表します。つまり、“abc” のような数値以外の文字列には 0 としてインデックスが作成されます。このタイプのビットスライス・インデックスは、文字列フィールドの値があるレコードを COUNT ですばやくカウントし、NULL のレコードをカウントしない場合に使用できます。
以下の例では、Salary はビットスライス・インデックスの候補となります。
SELECT AVG(Salary) FROM SalesPerson
ビットスライス・インデックスは、WHERE 節を使用するクエリで集約計算に使用できます。これは、WHERE 節に多数のレコードが含まれる場合に最も効果的です。以下の例では、SQL オプティマイザは多くの場合、Salary にビットスライス・インデックス (定義されている場合) を使用します。その場合、Region でも、定義されたビットマップを使用するか、Region にビットマップ一時ファイルを生成して、ビットマップ・インデックスが使用されます。
SELECT AVG(Salary) FROM SalesPerson WHERE Region=2
ただし、WHERE 条件がインデックスにより満たされず、集約されるフィールドを含むテーブルを読み取ることによって実行されなければならない場合には、ビットスライス・インデックスは使用されません。以下の例では、Salary でビットスライス・インデックスを使用しません。
SELECT AVG(Salary) FROM SalesPerson WHERE Name LIKE '%Mc%'
ビットスライス・インデックスは、数値を含むすべてのフィールドに対して定義できます。InterSystems SQL では、ObjectScript $FACTOR 関数で説明されているように、scale パラメータを使用して小数をビット文字列に変換します。ビットスライス・インデックスは、データ型が文字列のフィールドに定義できます。この場合、数値以外の文字列データ値は、ビットスライス・インデックスを定義するために 0 として扱われます。
システムで割り当てた行 ID に正整数値が指定されているテーブルのフィールドや、%BID プロパティが定義されているテーブル (ビットマップ (およびビットスライス) インデックスのサポート用) のフィールドにビットスライス・インデックスを定義できます。
ビットスライス・インデックスは、複数のフィールドの連結ではなく、単一のフィールド名にのみ定義できます。WITH DATA 節は指定できません。
次に示す例では、ビットスライス・インデックスとビットマップ・インデックスを比較しています。行 1、2、および 3 の値 1、5、および 22 にビットマップ・インデックスを作成すると、ビットマップ・インデックスは以下の値に対してインデックスを作成します。
^gloI("bitmap",1,1)= "100"
^gloI("bitmap",5,1)= "010"
^gloI("bitmap",22,1)="001"
行 1、2、および 3 の値 1、5、および 22 にビットスライス・インデックスを作成すると、まず、その値が以下のビット値に変換されます。
1 = 00001
5 = 00101
22 = 10110
その後で、以下に示すビットに対してインデックスを作成します。
^gloI("bitslice",1,1)="110"
^gloI("bitslice",2,1)="001"
^gloI("bitslice",3,1)="011"
^gloI("bitslice",4,1)="000"
^gloI("bitslice",5,1)="001"
この例では、ビットマップ・インデックスの値 22 には 1 つのグローバル・ノードの設定が必要になります。ビットスライス・インデックスの値 22 には 3 つのグローバル・ノードの設定が必要になります。
INSERT または UPDATE では、単一のビット文字列ではなく、すべての n ビットスライスでビットを設定する必要があることに注意してください。このような追加のグローバル設定操作は、ビットスライス・インデックスの入力に関連する INSERT 操作と UPDATE 操作のパフォーマンスに影響を及ぼすことがあります。INSERT、UPDATE、または DELETE 操作を使用してビットスライス・インデックスを生成および維持すると、ビットマップ・インデックスや通常のインデックスを使用する場合よりも速度が遅くなります。複数のビットスライス・インデックスを維持したり、頻繁に更新されるフィールドでビットスライス・インデックスを維持すると、パフォーマンス・コストが増える可能性があります。
揮発性のテーブル (多数の INSERT 操作、UPDATE 操作および DELETE 操作が実行されるもの) では、ビットスライス・インデックス用のストレージは徐々に効率が低下する可能性があります。%SYS.Maint.BitmapOpens in a new tab ユーティリティ・メソッドは、ビットマップ・インデックスとビットスライス・インデックスの両方を圧縮して、元の高い効率を復元します。詳細は、"ビットマップ・インデックスの維持" を参照してください。
列指向インデックス
列指向インデックスは、頻繁にクエリされるものの、テーブルに基盤となる行ストレージ構造があるフィールドに使用します。既定では、テーブルのそれぞれの行が $LIST として別々のグローバル添え字で格納されます。列指向インデックスには、特定のフィールドのデータが圧縮ベクトル化形式で保存されます。
InterSystems SQL DDL を使用して列指向インデックスを定義するには、次のように CREATE INDEX の CREATE COLUMNAR INDEX 構文を使用します。
CREATE COLUMNAR INDEX indexName ON table(column)
永続クラスに列指向インデックスを定義するには、次のように、定義するインデックスに type = columnar キーワードを指定します。
Index indexName ON propertyName [ type = columnar ]
以下の DDL の例は、テーブルの特定の列に列指向インデックスを定義する方法を示しています。
CREATE TABLE Sample.BankTransaction (
AccountNumber INTEGER,
TransactionDate DATE,
Description VARCHAR(100),
Amount NUMERIC(10,2),
Type VARCHAR(10))
CREATE COLUMNAR INDEX AmountIndex
ON Sample.BankTransaction(Amount)
このテーブルの Amount 列に対して AVG による集約計算を実行し、その結果の表示を預金額のみに絞り込むとします。
SELECT AVG(Amount) FROM Sample.BankTransaction WHERE Type = 'Deposit'
この計算では、1 つの列 (Amount) の一部の行 (WHERE Type = 'Deposit') のみを必要とするとき、メモリに各 $LIST グローバルをロードする必要があります。列指向インデックスを定義したフィールドに対する AVG 計算の実行でクエリ・プランからアクセスする情報は、$LIST グローバルから直接取得されるのではなく、この列指向インデックスから取得されます。
シリアル・プロパティやサブクラスには列指向インデックスを定義できません。ただし、サブクラスの非シリアル・プロパティ (%Integer など) にはインデックスを定義できます。
列指向インデックスはビットマップ・インデックスに類似していますが、等値条件ではビットマップ・インデックスよりもわずかに効率が低下します。ビットマップ・インデックスでは値ごとにすでにビット文字列が存在しますが、列指向インデックスの場合は、ベクトル化演算を実行して列指向インデックスから値を取得します。範囲条件では、列指向インデックスの方が効率的であることが普通です。ビットマップ・インデックスでは複数のビット文字列を結合する必要がありますが、列指向インデックスでは、1 回のベクトル化演算で同じ演算をこなすことができます。
列指向インデックスとテーブルのストレージ・レイアウトの定義の詳細は、"SQL テーブルのストレージ・レイアウトの選択" を参照してください。
インデックスの構築
インデックスは以下のように構築または再構築できます。
-
BUILD INDEX SQL コマンドを使用して、指定したインデックスを構築するか、テーブル、スキーマ、または現在のネームスペースに対して定義したすべてのインデックスを構築します。このオプションは、本稼働システムで使用しても安全です。
-
管理ポータルを使用して、指定したクラス (テーブル) のインデックスをすべて再構築します。
-
%BuildIndices() メソッド (または %BuildIndicesAsync() メソッド) を使用します。
インデックス・システムの構築でお勧めできる方法は、BUILD INDEX SQL コマンドを使用することです。インデックスの構築は、以下を実行します。
-
現在のインデックスの内容を削除します。
-
メインのテーブルをスキャンし (各行を読み取り)、テーブルの各行にインデックスのエントリを追加します。必要に応じ、$SortBegin と $SortEnd を使用して、並列実行と効率的なバッチ並べ替えのための低レベル最適化を適用します。
本稼働システムで BUILD INDEX を使用する場合、目的のインデックスは一時的に選択不可とされます。したがって、構築中のインデックスをクエリで使用することはできません。このインデックスを使用するクエリはパフォーマンスが低下します。
BUILD INDEX によるインデックスの構築
クラス・レベルまたは DDL レベルでインデックスを作成した後は、BUILD INDEX コマンドを使用して、そのインデックスを構築する必要があります。この文を使用すると、ネームスペースのすべてのインデックス、スキーマのすべてのインデックス、またはコマンドで指定したインデックスのみを構築できます。既定では、各テーブルのインデックスを作成する前に、そのテーブルに対するエクステント・ロックが取得されます。インデックスの作成が終了するとロックが解除され、そのインデックスをアクティブ・システムで安全に使用できるようになります。構築中のインデックスをクエリで使用することはできません。BUILD INDEX コマンドの実行中に INSERT コマンドでテーブルに挿入されたデータまたは UPDATE コマンドで更新されたテーブルのデータは、構築プロセスに取り込まれます。
BUILD INDEX では、発生したエラーがあれば、現在のプロセスに対するジャーナル設定を使用してログに記録されます。%NOLOCK オプションを指定してロック動作を無効化でき、%NOJOURN オプションを指定してジャーナル動作を無効化できます。
以下の例では、MyApp.Salesperson クラスにインデックスを構築します。
BUILD INDEX FOR TABLE MyApp.SalesPerson
BUILD INDEX FOR TABLE MyApp.SalesPerson INDEX NameIdx, SSNKey
1 番目の文で、指定した名前のテーブル (クラス) のインデックスをすべて構築しています。2 番目の文で、NameIdx インデックスと SSNKey インデックスのみを構築しています。
管理ポータルによるインデックスの構築
テーブルに既存のインデックスを構築 (インデックスを再構築) するには、以下の操作を実行します。
-
管理ポータルで、[システムエクスプローラ]、[SQL] の順に選択します。ページ上部の
[切り替え]
オプションを使ってネームスペースを選択します。利用可能なネームスペースのリストが表示されます。ネームスペースの選択後に、画面の左側にある [スキーマ] ドロップダウン・リストを選択します。これには、現在のネームスペースのスキーマのリストと、各スキーマに関連付けられているテーブルまたはビューがあるかどうかを示すブーリアン・フラグが表示されます。
-
このリストからスキーマを選択すると、[スキーマ] ボックスに表示されます。上記と同様に、ドロップダウン・リストでは、テーブル、システム・テーブル、ビュー、プロシージャ、またはスキーマに属するすべてを選択できます。[テーブル] または [すべて] を選択し、[テーブル] フォルダを開いて、このスキーマのテーブルのリストを開きます。テーブルがない場合は、フォルダを開くと空白ページが表示されます([テーブル] または [すべて] を選択しない場合は、[テーブル] フォルダを開くとネームスペース全体のテーブルがリストされます)。
-
一覧表示されているテーブルのいずれかを選択します。これにより、テーブルの
[カタログの詳細]
が表示されます。
Caution:
他のユーザがテーブルのデータにアクセスしている間は、この方法でインデックスを再構築しないでください。アクティブ・システム上でインデックスを再構築するには、BUILD INDEX を使用するか、プログラムによる方法を使用します。
プログラミングによるインデックスの構築
インデックスを作成するテーブルに %PersistentOpens in a new tab クラスによって用意されている %BuildIndices() メソッドと %BuildIndicesAsync() メソッドを使用することもできます。これらのメソッドは、InterSystems IRIS の既定のストレージ構造を使用しているクラス向けにのみ提供されています。これらのメソッドを呼び出すには、指定のクラスにインデックス定義を 1 つ以上追加してコンパイルしておく必要があります。メソッドの詳細は、以下のリンクからクラスリファレンスのページを参照してください。
インデックスの検証
以下のメソッドのいずれかを使用して、インデックスを検証できます。
両方のメソッドは、指定されたテーブルの 1 つまたは複数のインデックスのデータ整合性を確認するほか、必要に応じて、検出されたインデックス整合性の問題を修正します。インデックス検証は、以下の 2 つの手順で実行されます。
-
テーブル (クラス) 内のすべての行 (オブジェクト) のインデックス・エンティティが適切に定義されていることを確認します。
-
各インデックスを詳しく調べて、インデックスが付いたすべてのエントリに対して、テーブル (クラス) 内に値および一致するエントリがあることを確認します。
いずれかのメソッドで不一致が見つかった場合は、オプションでそのメソッドでインデックスの構造またはコンテンツを修正できます。標準インデックス、ビットマップ・インデックス、ビットマップ・エクステント・インデックス、およびビットスライス・インデックスを検証し、必要に応じて修正できます。既定では、どちらのメソッドもインデックスを検証しますが、修正はしません。
SetMapSelectability()Opens in a new tab を使用して、%ValidateIndices() 引数に autoCorrect=1 と lockOption>0 の両方を指定している場合にのみ、%ValidateIndices() を使用して READ アクティブ・システム上と WRITE アクティブ・システム上のインデックスを修正できます。%ValidateIndices() は処理が著しく遅いので、アクティブ・システム上でインデックスを構築するには %BuildIndices() の使用をお勧めします。
一般に、%ValidateIndices() はターミナルから実行します。出力は現在のデバイスに表示されます。このメソッドは、指定したインデックス名の %List、または指定したテーブル (クラス) に定義したすべてのインデックスに適用できます。これは、指定されたクラスに由来するインデックスにのみ機能します。インデックスがスーパークラスに由来している場合は、そのスーパークラスで %ValidateIndices() を呼び出すことで、そのインデックスを検証できます。これは READONLY クラスではサポートされていません。
シャード・クラスのインデックスの検証
%ValidateIndices() は、シャード・クラスおよびシャード・マスタ・クラス・テーブル (Sharded=1) でサポートされます。%ValidateIndices は、クラス・メソッドとして直接呼び出すことも、シャード・マスタ・クラスで $SYSTEM.OBJ.ValidateIndices から呼び出すこともできます。これにより、各シャードのシャード・ローカル・クラスでインデックス検証が実行され、シャード・マスタの呼び出し元に結果が返されます。シャード・クラスで %ValidateIndices() を使用すると、詳細フラグは強制的に 0 に設定されます。現在のデバイスへの出力はありません。検出/修正された問題がある場合、参照渡しの errors() 配列で返されます。
クエリ処理でのインデックスの使用
インデックスは、頻繁に要求されるデータのサブセットをソートして管理することで、クエリを最適化するメカニズムを提供します。どのフィールドにインデックスを定義するかを決定する際にも注意が必要です。インデックスが少なすぎる場合やインデックスに誤りがある場合は主要なクエリの速度が大きく低下します。また、インデックスが多すぎる場合は、INSERT や UPDATE のパフォーマンスが低下します (インデックス値の設定や更新が必要になるため)。
インデックスの対象
インデックスの追加によってクエリのパフォーマンスが向上するかどうかを判断するには、管理ポータルの SQL インタフェースからクエリを実行して、[パフォーマンス] のグローバル参照の数をメモします。インデックスを追加してからクエリを再度実行して、グローバル参照の数をメモします。インデックスが有用な場合は、グローバル参照の数が少なくなります。インデックスの使用を抑止するには、WHERE 節または ON 節の条件の前に %NOINDEX キーワードを使用します。
JOIN で指定したフィールド (プロパティ) のインデックスを作成します。LEFT OUTER JOIN では、左のテーブルから開始し、その後、右のテーブルを調査します。そのため、右のテーブルのフィールドからインデックスを作成する必要があります。以下の例では、T2.f2 のインデックスを作成します。
FROM Table1 AS T1 LEFT OUTER JOIN Table2 AS T2 ON T1.f1 = T2.f2
INNER JOIN では、両方の ON 節のフィールドに対するインデックスが必要です。
プラン表示を実行して、最初のマップをたどります。クエリ・プランの最初の箇条項目が "Read master map" の場合や、最初の箇条項目が "Read master map" のモジュールをクエリ・プランが呼び出す場合は、クエリの最初のマップはインデックス・マップではなくマスタ・マップになります。マスタ・マップは、データに対するインデックスではなくデータ自体を読み取るため、ほとんどの場合、これは非効率的なクエリ・プランになります。テーブルが比較的小さなものでない限り、このクエリを再実行したときにクエリ・プランの最初のマップに [インデックス・マップの読み取り] と表示されるようにインデックスを作成する必要があります。
WHERE 節の等値条件で指定されるフィールドのインデックスを作成します。
WHERE 節の範囲条件で指定されるフィールドや GROUP BY 節および ORDER BY 節で指定されるフィールドのインデックスを作成することが必要になる場合もあります。
範囲条件に基づくインデックスでは、クエリの速度が遅くなる場合があります。大部分の行が指定された範囲条件を満たす場合にこのようになる可能性があります。例えば、レコードの大部分が前の日付を持つデータベースでクエリ節 WHERE Date < CURRENT_DATE を使用する場合に、Date にインデックスを作成すると、クエリの速度が大幅に低下します。この原因は、クエリ・オプティマイザは、範囲条件で返される行は比較的少ないと仮定し、この状況に合わせて最適化するからです。これが発生しているかどうかは、範囲条件の前に %NOINDEX を配置してクエリを再度実行することで判断できます。
インデックスが作成されているフィールドを使用して比較を実行する場合、その比較に指定するフィールドの照合タイプは、対応するインデックスの照合タイプと同じにする必要があります。例えば、SELECT の WHERE 節または JOIN の ON 節の Name フィールドは、その Name フィールドに定義されたインデックスと同じ照合にする必要があります。フィールドの照合とインデックスの照合に不一致があると、インデックスの効果が低下するか、インデックスがまったく使用されなくなります。詳細は、このドキュメントの “インデックスの定義と構築” の章の "インデックス照合" を参照してください。
インデックスの作成方法および使用可能なインデックスのタイプとオプションの詳細は、"InterSystems SQL リファレンス" の "CREATE INDEX" コマンドと、このドキュメントの “インデックスの定義と構築” の章を参照してください。
インデックス構成オプション
以下のシステム全体の構成メソッドは、クエリでインデックスの使用を最適化するために使用できます。
詳細は、"システム管理ガイド" にリストされている "SQL およびオブジェクトの設定ページ" を参照してください。
%ALLINDEX、%IGNOREINDEX、%NOINDEX の使用法
FROM 節では、%ALLINDEX と %IGNOREINDEX の optimize-option キーワードをヒントとしてサポートしています。これらの optimize-option キーワードは、クエリ内のすべてのインデックスの使用を制御します。
条件レベル・ヒント %NOINDEX を使用すると、特定の条件のインデックスの使用に対する例外を指定できます。%NOINDEX ヒントは、インデックスを使用しない各条件の前に配置します。例えば、WHERE %NOINDEX hiredate < ? のようにします。通常、この方法は条件によって圧倒的多数のデータが選択される (または選択されない) 場合に使用します。「より小さい (<)」または「より大きい (>)」条件では、通常、条件レベル・ヒント %NOINDEX を使用すると効果的です。等価条件では、条件レベル・ヒント %NOINDEX を使用しても効果はありません。結合条件では、%NOINDEX は、ON 節の結合でサポートされます。
%NOINDEX キーワードを使用すると、FROM 節で確立されたインデックス最適化をオーバーライドできます。以下の例では、%ALLINDEX 最適化のキーワードが E.Age 条件を除くすべての条件テストに適用されます。
SELECT P.Name,P.Age,E.Name,E.Age
FROM %ALLINDEX Sample.Person AS P LEFT OUTER JOIN Sample.Employee AS E
ON P.Name=E.Name
WHERE P.Age > 21 AND %NOINDEX E.Age < 65
インデックス使用状況の分析
SQL クエリ・キャッシュで定義したインデックスの使用状況分析に使用できるツールが 2 つあります。
インデックスのリスト表示
INFORMATION.SCHEMA.INDEXESOpens in a new tab 永続クラスは、現在のネームスペース内のすべての列インデックスに関する情報を表示します。これは、インデックス付けされた列ごとに 1 つのレコードを返します。これは、インデックスの名前や、インデックスのマップ先のテーブル名、列名など、さまざまなインデックス・プロパティを提供します。各列レコードには、インデックス・マップにおける列の順序位置も含まれます。この値は、インデックスが複数の列にマップされない限り 1 です。また、ブーリアン・プロパティ PRIMARYKEY および NONUNIQUE も提供します (0= インデックス値は一意である必要があります)。
以下の例では、現在のネームスペース内のすべての非システム・インデックスについて、インデックスに属する列ごとに 1 行が返されます。
SELECT Index_Name,Table_Schema,Table_Name,Column_Name,Ordinal_Position,
Primary_Key,Non_Unique
FROM INFORMATION_SCHEMA.INDEXES WHERE NOT Table_Schema %STARTSWITH '%'
管理ポータルの SQL インタフェースの [カタログの詳細] の [マップ/インデックス] オプションを使用して、選択したテーブルのインデックスをリスト表示できます。このオプションでは、インデックスごとに 1 行と、INFORMATION.SCHEMA.INDEXESOpens in a new tab で提供されないインデックス情報が表示されます。
メソッドのオープン、存在確認、および削除
InterSystems IRIS インデックス作成機能は、以下の操作をサポートします。
-
インデックス・キーによるインスタンスのオープン
-
インスタンスが存在するかどうかの確認
-
インスタンスの削除
インデックス・キーによるインスタンスのオープン
ID キー、主キー、または一意のインデックスの場合、indexnameOpen() メソッド (indexname はインデックスの名前) を使用することによって、インデックスのプロパティ値が指定値と一致するオブジェクトを開くことができます。このメソッドには、インデックス内の各プロパティに対応する 1 つの引数があるため、メソッドには 3 つ以上の引数があります。
-
最初の引数は、それぞれインデックス内のプロパティに対応します。
-
最後から 2 番目の引数は、オブジェクトを開くときに使用される並行処理値を指定します (使用可能な並行処理の設定は、"クラスの定義と使用" の “オブジェクト同時処理” に示されています)。
-
最後の引数は、メソッドがインスタンスを開くことに失敗した場合に、%Status コードを受け取ることができます。
このメソッドは、一致するインスタンスを見つけると OREF を返します。
例えば、クラスに以下のインデックス定義が含まれているとします。
Index SSNKey On SSN [ Unique ];
そして、参照されたオブジェクトがディスクに保存され、一意の ID 値を持つ場合、以下のようにメソッドを呼び出すことができます。
SET person = ##class(Sample.Person).SSNKeyOpen("111-22-3333",2,.sc)
正常に完了すると、このメソッドによって、SSN プロパティの値が 111–22–3333 である Sample.Person のインスタンスの OREF に、person の値が設定されます。
メソッドへの 2 番目の引数は並行処理値を指定し、上の例では 2 (共有) です。3 番目の引数は、オプションの %Status コードを保持します。指定された値と一致するオブジェクトをメソッドが見つけられなかった場合、エラー・メッセージがステータス・パラメータ sc に書き込まれます。
このメソッドは、%Compiler.Type.Index.Open() メソッドとして実装されます。このメソッドは、%Persistent.Open()Opens in a new tab メソッドおよび %Persistent.OpenId()Opens in a new tab メソッドに似ています。異なるのは、このメソッドが、OID 引数や ID 引数ではなくインデックス定義内のプロパティを使用する点です。
インスタンスが存在するかどうかの確認
indexnameExists() メソッド (indexname はインデックスの名前) は、メソッドの引数で指定されているインデックス・プロパティ値を持つインスタンスが存在するかどうかを確認します。このメソッドには、インデックス内の各プロパティに対応する 1 つの引数があり、その最後のオプションの引数は、オブジェクトの ID が指定値と一致する場合に、その ID を受け取ることができます。このメソッドは、ブーリアン値を返し、成功 (1) または失敗 (0) を示します。このメソッドは、%Compiler.Type.Index.Exists() メソッドとして実装されます。
例えば、クラスに以下のインデックス定義が含まれているとします。
Index SSNKey On SSN [ Unique ];
そして、参照されたオブジェクトがディスクに保存され、一意の ID 値を持つ場合、以下のようにメソッドを呼び出すことができます。
SET success = ##class(Sample.Person).SSNKeyExists("111-22-3333",.id)
正常に完了すると、success が 1 になり、id には、検出されたオブジェクトと一致する ID が含まれます。
このメソッドは、以下を除くすべてのインデックスの値を返します。
インスタンスの削除
indexnameDelete() メソッド (indexname はインデックスの名前) は、Unique、PrimaryKey、IdKey の各インデックスに使用します。このメソッドは、指定されたキーのプロパティ/列の値に一致するインスタンスを削除します。オプションの引数が 1 つあり、これを指定して操作の並行処理を指定できます。このメソッドは %Status コードを返します。%Compiler.Type.Index.Delete() メソッドとして実装されます。
FeedbackOpens in a new tab