Skip to main content

This documentation is for an older version of this product. See the latest version of this content.Opens in a new tab

インデックスの定義と作成

概要

インデックスとは、InterSystems IRIS® データ・プラットフォームがクエリや他の操作の最適化に使用できる、永続クラスにより管理される構造のことです。

インデックスは、テーブル内のフィールドの値に対して定義することも、クラス内の対応するプロパティに対して定義することもできます(また、インデックスは複数のフィールド/プロパティを組み合わせた値に対して定義することもできます)。SQL フィールドとテーブルの構文、またはクラス・プロパティ構文を使用して定義されているかどうかに関係なく、同じインデックスが作成されます。特定のタイプのフィールド (プロパティ) を定義すると、InterSystems IRIS によってインデックスが自動的に定義されます。データを格納したフィールドや、データを確実に派生できるフィールドに、追加のインデックスを定義できます。InterSystems IRIS には、さまざまなタイプのインデックスが用意されています。同じフィールド (プロパティ) に複数のインデックスを定義して、目的が異なるさまざまなタイプのインデックスを用意できます。

InterSystems IRIS では、データベースに対してデータの挿入、更新、または削除の操作を実行すると、SQL フィールドとテーブルの構文またはクラス・プロパティ構文を使用しているかどうかに関係なく、既定ではインデックスが生成され、維持されます。この既定はデータへの変更を迅速に実行するためにオーバーライドできます (%NOINDEX キーワードを使用)。その後で、個別の操作として対応するインデックスをビルドまたはリビルドします。テーブルにデータを移入する前にインデックスを定義できます。さらに、すでにデータが移入されているテーブルにインデックスを定義して、それから別の操作としてインデックスを構築することもできます。

InterSystems IRIS では、SQL クエリを作成および実行するときに、利用可能なインデックスが活用されます。既定では、クエリのパフォーマンスが最適化されるように、使用するインデックスが選択されます。必要に応じて、特定のクエリまたはすべてのクエリに 1 つ以上のインデックスが使用されないようにするために、この既定をオーバーライドできます。インデックスの最適な使用方法の詳細は、"“インデックスの作成と定義”" ページの "インデックスの使用" のセクションを参照してください。

インデックスの属性

すべてのインデックスに一意の名前があります。この名前は、レポート作成、インデックス構築、インデックス削除をはじめとするデータベース管理に使用します。他の SQL エンティティと同様に、インデックスにも SQL インデックス名および対応するインデックス・プロパティ名の両方があります。これらの名前は、許可されている文字、大文字と小文字の区別、および最大長が異なります。SQL CREATE INDEX コマンドを使用して定義する場合、システムによって対応するインデックス・プロパティ名が生成されます。永続クラス定義を使用して定義する場合、SqlName キーワードにより、ユーザは異なる SQL インデックス名 (SQL マップ名) を指定することができます。管理ポータルの SQL インタフェース [カタログの詳細] には、各インデックスの SQL インデックス名 ( [SQL マップ名] ) および対応するインデックス・プロパティ名 ([インデックス名]) が表示されます。

インデックス・タイプは 2 つのインデックス・クラス・キーワード、Type および Extent により定義されます。InterSystems IRIS で使用可能なインデックスのタイプは以下のとおりです。

  • 標準インデックス (Type = index) — インデックス値と、値を収めた行の RowID を関連付ける永続配列です。ビットマップ・インデックス、ビットスライス・インデックス、またはエクステント・インデックスとして明示的に定義されていないインデックスは、すべて標準インデックスです。

  • ビットマップ・インデックス (Type = bitmap) — 指定されたインデックス値に対応する一連の RowID 値を表すために一連のビット文字列を使用する特殊な種類のインデックスです。InterSystems IRIS には、ビットマップ・インデックス用のパフォーマンス最適化機能が数多く用意されています。

  • ビットスライス・インデックス (Type = bitslice) — 合計や値域条件など、特定の式についてきわめて高速な評価を可能にする特殊な種類のインデックスです。ビットスライス・インデックスは、特定の SQL クエリで自動的に使用されます。

  • 列指向インデックス (Type = columnar) — 基盤となるデータが複数の行にわたって格納されている列に対してきわめて高速なクエリを実行できる特殊な種類のインデックスです。特に、フィルタリングと集約の処理を伴うクエリで効果的です。列指向インデックスは、2022.2 の試験的機能です。

  • エクステント・インデックス — エクステント内のすべてのオブジェクトのインデックスです。詳細は、"クラス定義リファレンス" の "Extent" インデックス・キーワードのページを参照してください。

1 つのテーブル (クラス) で使用できるインデックスの最大数は 400 です。

ストレージ・タイプとインデックス

ここで説明するインデックス機能は、永続クラスに保存されたデータに適用されます。InterSystems SQL は、InterSystems IRIS で既定のストレージ構造である %Storage.Persistent (%Storage.Persistent にマップしたクラス) を使用して保存したデータと、%Storage.SQL (%Storage.SQL にマップしたクラス) を使用して保存したデータに対応するインデックス機能をサポートしています。%Storage.SQL にマップしたクラスのインデックスは、機能インデックス・タイプを使用することで定義できます。このインデックスは、既定のストレージを使用するクラスのインデックスと同じ方法で定義しますが、以下の特別な考慮事項が付随します。

詳細は %Library.FunctionalIndexOpens in a new tab を参照してください。

インデックスのグローバル名

インデックス・データの保存先となるグローバルの添え字付き名前は、該当のデータをテーブルに保存するグローバルの名前で決まります。これらの名前は、テーブルを定義する USEEXTENTSET クラス・パラメータと DEFAULTGLOBAL クラス・パラメータの値に依存して、永続クラスで決まるか、CREATE TABLE 文に %CLASSPARAMETER キーワードを使用することで決まります。USEEXTENTSET と DEFAULTGLOBAL の詳細は、それぞれ "ハッシュ定義のグローバル名" と "ユーザ定義のグローバル名" を参照してください。

マスタ・マップ

すべてのテーブルにマスタ・マップが自動的に定義されます。マスタ・マップは、インデックスではありません。マップの添え字フィールドを使用して、データ自体に直接アクセスするマップです。既定では、マスタ・マップの添え字フィールドは、システム定義の RowID フィールドです。既定では、RowID フィールドを使用したこの直接データ・アクセスは、SQL マップ名 (SQL インデックス名) IDKEY で表されます。

既定では、ユーザ定義の主キーは IDKEY ではありません。ほとんどの場合、RowID の整数を使用したマスタ・マップ検索の方が主キー値による検索よりも効率的であるためです。ただし、主キーを IDKEY として指定した場合は、主キー・インデックスがテーブルのマスタ・マップとして定義され、SQL マップ名は主キー SQL インデックス名になります。

単一フィールドの主キー/IDKEY の場合、主キー・インデックスがマスタ・マップになりますが、マスタ・マップのデータ・アクセス列は RowID のままです。これは、レコードの一意の主キー・フィールド値とその RowID 値の間には 1 対 1 の一致があり、また、RowID の方が効率的な検索であると考えられるためです。複数フィールドの主キー/IDKEYの場合、マスタ・マップに主キー・インデックス名が指定され、マスタ・マップのデータ・アクセス列は主キー・フィールドになります。

管理ポータルの SQL の [カタログの詳細] タブ を使用して、マスタ・マップ定義を表示できます。このタブには、マスタ・マップ・データが格納されるグローバル名などの項目が表示されます。SQL および既定のストレージの場合、このマスタ・マップ・グローバルは既定で ^package.classnameD に設定され、あいまいさを回避するために、ネームスペースが記録されます。カスタム・ストレージの場合は、マスタ・マップのデータ・ストレージ・グローバルは定義されません。DATALOCATIONGLOBAL クラス・パラメータを使用して、データ・ストレージ・グローバル名を指定できます。

SQL および既定のストレージの場合、添え字付き名前を持つグローバルである ^package.classnameD または ^hashpackage.hashclass.1 にマスタ・マップ・データが格納されます (詳細は、"インデックスのグローバル名" を参照してください)。グローバル名には、対応する SQL テーブル名ではなく、永続クラス名が指定されます。また、グローバル名では大文字と小文字が区別されます。グローバル名を ZWRITE に渡すことで、マスタ・マップ・データを表示できます。

マスタ・マップを使用したデータ・アクセスは、テーブルが大きい場合は特に、非効率的です。このことから、WHERE 条件や JOIN 操作などの操作で指定したデータ・フィールドへのアクセスで使用できるインデックスをユーザ側で定義しておくことをお勧めします。

自動定義されたインデックス

テーブルを定義するときに、特定のインデックスが自動的に定義されます。テーブルを定義するときに以下のインデックスが自動的に生成され、テーブルのデータを追加または変更するときに、これらのインデックスに値が入力されます。以下の定義について説明します。

  • IDKEY でない主キーを定義すると、タイプ Unique の対応するインデックスが生成されます。主キー・インデックスの名前は、ユーザが指定した名前にすることも、テーブルの名前から導出することもできます。例えば、名前のない主キーを定義した場合、対応するインデックスの名前は tablenamePKEY# になります (# は、それぞれの一意の主キー制約の連続する整数です)。

  • UNIQUE フィールドを定義すると、tablenameUNIQUE# という名前で UNIQUE フィールドごとにインデックスが生成されます (# は、それぞれの一意の主キー制約の連続する整数です)。

  • UNIQUE 制約を定義すると、指定された名前で UNIQUE 制約ごとにインデックスが生成され、一意の値を共に定義するフィールドにインデックスが付けられます。

  • シャード・キーを定義すると、ShardKey という名前のシャード・キー・フィールドにインデックスが生成されます。

管理ポータルの SQL の [カタログの詳細] タブを使用して、これらのインデックスを表示できます。CREATE INDEX コマンドを使用すると、UNIQUE フィールド制約を追加できます。DROP INDEX コマンドを使用すると、UNIQUE フィールド制約を削除できます。

既定では、RowID フィールドに IDKEY インデックスが生成されます。IDENTITY フィールドを定義しても、インデックスは生成されません。ただし、IDENTITY フィールドを定義して、そのフィールドを主キーにすると、InterSystems IRIS は IDENTITY フィールドに IDKEY インデックスを定義して主キー・インデックスにします。以下に例を示します。

CREATE TABLE Sample.MyStudents (
           FirstName VARCHAR(12),
           LastName VARCHAR(12),
           StudentID IDENTITY,
           CONSTRAINT StudentPK PRIMARY KEY (StudentID) )

同様に、IDENTITY フィールドを定義して、そのフィールドに UNIQUE 制約を適用すると、InterSystems IRIS は IDENTITY フィールドに明示的に IdKey/Unique インデックスを定義します。以下に例を示します。

CREATE TABLE Sample.MyStudents (
           FirstName VARCHAR(12),
           LastName VARCHAR(12),
           StudentID IDENTITY,
           CONSTRAINT StudentU UNIQUE (StudentID) )

こうした IDENTITY インデックスの作成処理は、明示的に定義された IdKey インデックスが存在しないことと、テーブルにデータが格納されていない場合にのみ実行されます。

ビットマップ・エクステント・インデックス

ビットマップ・エクステント・インデックスは、テーブルの特定のフィールドではなく、テーブルの行のビットマップ・インデックスです。ビットマップ・エクステント・インデックスでは、各ビットは連続した RowID の整数値を表し、各ビットの値は対応する行が存在しているかどうかを示します。InterSystems SQL はこのインデックスを使用して、テーブル内のレコード (行) 数を返す COUNT(*) のパフォーマンスを改善します。テーブルには最大 1 つのビットマップ・エクステント・インデックスを指定できます。複数のビットマップ・エクステント・インデックスを作成しようとすると、SQLCODE -400 エラーが発生し、メッセージ %msg ERROR #5445: 複数のエクステント・インデックスが定義されています: DDLBEIndex が表示されます。

  • CREATE TABLE を使用して定義されたテーブルでは、自動的にビットマップ・エクステント・インデックスが定義されます。この自動的に生成されたインデックスには、インデックス名 DDLBEIndex および SQL マップ名 %%DDLBEIndex が割り当てられます。

  • 永続クラスとして定義されたテーブルでは、自動的にビットマップ・エクステント・インデックスが定義されません。ビットマップを持たない永続クラスにビットマップ・インデックスを追加すると、InterSystems IRIS は自動的にビットマップ・エクステント・インデックスを生成します。この生成されたビットマップ・エクステント・インデックスには、$ClassName のインデックス名と SQL マップ名が割り当てられています (ClassName は、テーブルの永続クラスの名前です)。

BITMAPEXTENT キーワードを指定した CREATE INDEX コマンドを使用して、テーブルにビットマップ・エクステント・インデックスを追加したり、自動的に生成されたビットマップ・エクステント・インデックスの名前を変更したりできます。詳細は、"CREATE INDEX" を参照してください。

管理ポータルの SQL の [カタログの詳細] タブ を使用して、テーブルのビットマップ・エクステント・インデックスを表示できます。テーブルに指定できるビットマップ・エクステント・インデックスは 1 つのみですが、別のテーブルを継承したテーブルは、それ自身のビットマップ・エクステント・インデックスと継承元のテーブルのビットマップ・エクステント・インデックスの両方と共にリストされます。例えば、Sample.Employee テーブルが Sample.Person テーブルを継承した場合、[カタログの詳細][マップ/インデックス] では、Sample.Employee に $Employee$Person の両方のビットマップ・エクステント・インデックスがリストされます。

多数の DELETE 操作が実行されるテーブルでは、ビットマップ・エクステント・インデックス用のストレージは徐々に効率が低下する可能性があります。BUILD INDEX コマンドを使用するか、管理ポータルでテーブルの [カタログの詳細] タブの [マップ/インデックス] オプションを選択し、[インデックス再構築] を選択して、ビットマップ・エクステント・インデックスを再構築することができます。

%SYS.Maint.BitmapOpens in a new tab ユーティリティ・メソッドでは、ビットマップ・インデックスおよびビットスライス・インデックスと同様にビットマップ・エクステント・インデックスが圧縮されます。詳細は、“ビットマップ・インデックスの維持” を参照してください。

%BuildIndices() メソッドを呼び出したときに、%BuildIndices()pIndexList 引数が指定されていない (すべての定義済みインデックスを構築する) 場合、pIndexList にビットマップ・エクステント・インデックスが名前で指定されている場合、または pIndexList に定義済みのビットマップ・インデックスが指定されている場合、このメソッドは既存のビットマップ・エクステント・インデックスを構築します。“プログラミングによるインデックスの構築” を参照してください。

インデックスの定義

インデックスを定義するには、以下の 2 つの方法があります。

DDL を使用したインデックスの定義

テーブルの定義に DDL 文を使用している場合、インデックスの生成および削除に以下の DDL コマンドを使用できます。

DDL インデックス・コマンドは以下を実行します。

  1. インデックスが追加または削除される、対応するクラス定義およびテーブル定義を更新します。変更されたクラス定義は、再コンパイルされます。

  2. 必要に応じて、データベースのインデックス・データを追加または削除します。CREATE INDEX コマンドは、現在データベースに保存されているデータを使用してインデックスを生成します。同様に、DROP INDEX コマンドは、データベースからインデックス・データ (実際のインデックス) を削除します。

クラス定義を使用したインデックスの定義

クラス定義のテキストを編集することで、%Persistent クラス定義にインデックス定義を追加できます。インデックスは、1 つ以上のインデックス・プロパティ式で定義され、必要に応じて 1 つ以上のオプションのインデックス・キーワードが続きます。以下の形式をとります。

INDEX index_name ON index_property_expression_list [index_keyword_list];

以下はその説明です。

  • index_name は、有効な識別子です。

  • index_property_expression_list は、インデックスの基準となる 1 つ以上のコンマ区切りのプロパティ式のリストです。

  • index_keyword_list は、角括弧で囲まれた、インデックス・キーワードのコンマ区切りリストです (オプション)。ビットマップ・インデックスまたはビットスライス・インデックスに、インデックスの Type を指定するために使用します。また、Unique インデックス、IdKey インデックス、または PrimaryKey インデックスを指定する場合にも使用します。(IdKey インデックスまたは PrimaryKey インデックスは、定義上、Unique インデックスでもあります)。インデックス・キーワードの完全なリストについては、"クラス定義リファレンス" を参照してください。

index_property_expression_list 引数は、1 つ以上のインデックス・プロパティ式で構成されています。インデックス・プロパティ式の構成要素は以下のとおりです。

  • インデックスの作成対象のプロパティの名前。

  • オプションの (ELEMENTS) 式または (KEYS) 式。これは、コレクションのサブ値に対するインデックス作成手段となります。インデックス・プロパティがコレクションでない場合、ユーザは BuildValueArray() メソッドを使用して、キーと要素を格納する配列を生成できます。キーと要素の詳細は、“コレクションのインデックス作成” のセクションを参照してください。

  • オプションの照合式。この式は、照合名と、必要に応じてそれに続く 1 つ以上のコンマ区切りの照合パラメータのリストで構成されます。インデックス照合は、Unique インデックス、IdKey インデックス、または PrimaryKey インデックスには指定できません。Unique または PrimaryKey インデックスの照合は、インデックスを生成するプロパティ (フィールド) から取得します。IdKey インデックスの照合は、常に EXACT になります。有効な照合名のリストについては、"InterSystems SQL の使用法" の “照合” の章にある “照合タイプ” のセクションを参照してください。

例えば、以下のクラス定義は、2 つのプロパティとそれぞれのプロパティに基づくインデックスを定義しています。

Class MyApp.Student Extends %Persistent [DdlAllowed]
{
 Property Name As %String;
 Property GPA As %Decimal;

 Index NameIDX On Name;
 Index GPAIDX On GPA;
}

より複雑なインデックス定義は以下のようになります。

 Index Index1 On (Property1 As SQLUPPER(77), Property2 AS EXACT);

インデックスを付けることができるプロパティ

以下の各プロパティにインデックスを作成できます。

  • データベースに格納されているプロパティ。

  • 格納されているプロパティから確実に派生できるプロパティ。

確実に派生できるものの、格納されていないプロパティでは、SQLComputed キーワードに True を定義する必要があります。プロパティ値の派生ではプロパティの計算コードを唯一の方法とする必要があります。プロパティを直接設定することはできません。

Transient として定義されており、かつ Calculated として定義されていない単純な (非コレクション) プロパティのケースなど、派生したプロパティの値を直接設定することが可能な場合、プロパティの値を直接設定すると、SQLComputeCode で定義されている計算がオーバーライドされ、格納されているプロパティから値を確実に派生させることはできません。このようなタイプの派生プロパティは、"非決定性" と呼ばれます(Calculated キーワードは、実際には、インスタンス・メモリが割り当てられていないことを意味します)。一般的には、インデックスを付けることができるのは、Calculated および SQLComputed として定義されている派生プロパティのみです。ただし、派生コレクションには例外があります。それは、派生し (SQLComputed)、Transient であり (格納されていない)、かつ Calculated として定義されていない (つまり、インスタンス・メモリがない) コレクションにはインデックスを付けることができるということです。

テキストの長さに制限があるプロパティでは、データを取り込むことはできても、プロパティの内容が、インデックスの添え字にするには長すぎることがあります。複数のフィールドを結合することで添え字には長すぎるプロパティになる複合インデックスも、テキスト長さ制限の対象となることがあります。しかし、一般的に、長い文字列に対するインデックスは、それによって他の値が特定されることはまれなので、インデックスとしての有用性は限られています。したがって、この場合はエラー・メッセージが表示され、インデックスにデータは保存されません。それでも、長いテキスト・フィールドをインデックスにする場合は、該当のプロパティの照合文字列を 128 文字に制限した TRUNCATE 照合を定義できます。

Note:

IdKey インデックスによって使用されるどのプロパティの値においても、そのプロパティが永続クラスのインスタンスへの有効な参照でない限り、連続する 2 つの垂直バー (||) は使用しないでください。この制限は、InterSystems SQL の内部メカニズムで必要とされています。IdKey プロパティ で || を使用すると、予測できない動作を起こす場合があります。

プロパティの組み合わせに対するインデックス

2 つ以上のプロパティ (フィールド) の結合にインデックスを作成できます。以下のように、クラス定義の中のインデックス定義の On 節を使用して、プロパティのリストを指定します。

Class MyApp.Employee Extends %Persistent [DdlAllowed]
{
 Property Name As %String;
 Property Salary As %Integer;
 Property State As %String(MAXLEN=2);

 Index MainIDX On(State,Salary);
}

複数のプロパティに対するインデックスは、以下のように、フィールド値の組み合わせを使用したクエリを実行する場合に便利です。

SELECT Name,State,Salary
  FROM Employee
  ORDER BY State,Salary

インデックス照合

Unique インデックス、PrimaryKey インデックス、または IdKey インデックスには、照合タイプを指定できません。その他のタイプのインデックスの場合、オプションで、インデックス定義で指定した各プロパティに照合タイプを指定できます。インデックスが適用される場合、インデックスの照合タイプは、プロパティ (フィールド) の照合タイプと一致している必要があります。

  1. インデックス定義に、明示的に指定されたプロパティの照合が含まれている場合、インデックスはその照合を使用します。

  2. インデックス定義に、明示的に指定されたプロパティの照合が含まれていない場合、インデックスはプロパティ定義で明示的に指定された照合を使用します。

  3. プロパティ定義に、明示的に指定された照合が含まれていない場合、インデックスはプロパティのデータ型の既定の照合を使用します。

例えば、Name プロパティが文字列として定義されていると、そのプロパティの既定は SQLUPPER 照合になります。Name に対するインデックスを定義すると、そのプロパティの照合が既定で取得され、そのインデックスも SQLUPPER を使用して定義されます。プロパティの照合とインデックスの照合が一致します。

ただし、異なる照合を適用する比較の場合 (例えば、WHERE %EXACT(Name)=%EXACT(:invar))、この使用法でのプロパティの照合タイプは、インデックスの照合タイプと一致しなくなります。プロパティ比較の照合タイプとインデックスの照合タイプの間に不一致があると、インデックスが使用されなくなる可能性があります。そのため、この場合は、Name プロパティのインデックスを照合 EXACT で定義することをお勧めします。JOIN 文の ON 節で照合タイプを指定すると (例えば、FROM Table1 LEFT JOIN Table2 ON %EXACT(Table1.Name) = %EXACT(Table2.Name))、ここで指定したプロパティの照合タイプとインデックスの照合タイプとの間の不一致が原因になり、InterSystems IRIS がインデックスを使用しなくなる可能性があります。

インデックスとプロパティとの間での照合の一致を制御するルールは以下のとおりです。

  • 照合タイプが一致する場合は、常にインデックスが最大限使用されます。

  • 照合タイプが不一致で、プロパティが EXACT 照合で指定されており (前述の説明を参照)、インデックスが別の照合を持っている場合は、インデックスが使用できるようにはなりますが、インデックス使用の効果は照合タイプが一致しているときよりも低下します。

  • 照合タイプが不一致で、プロパティの照合が EXACT ではなく、プロパティの照合がインデックスの照合と一致しない場合は、インデックスが使用されなくなります。

インデックス定義でプロパティの照合を明示的に指定するには、以下の構文を使用します。

Index IndexName On PropertyName As CollationName;

以下はその説明です。

  • IndexName は、インデックスの名前です。

  • PropertyName はインデックスが付けられているプロパティです。

  • CollationName はインデックスに使用されている照合タイプです。

以下はその例です。

Index NameIDX On Name As Exact;

異なるプロパティは、異なる照合タイプを持つことができます。例えば、以下の例では、F1 プロパティは SQLUPPER 照合を使用する一方で、F2 は EXACT 照合を使用します。

Index Index1 On (F1 As SQLUPPER, F2 As EXACT);

推奨される照合タイプのリストについては、"InterSystems SQL の使用法" の “照合” の章にある “照合タイプ” のセクションを参照してください。

Note:

UniquePrimaryKey、または 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

以下はその説明です。

  • BuildValueArray() メソッドの名前は、複合メソッドに対する一般的な方法でプロパティ名から派生します。

  • 最初の引数はプロパティ値です。

  • 2 番目の引数は、参照によって渡される配列です。これは、キーによって添え字が付けられた配列が要素と等しい、キーと要素のペアを含む配列です。

  • このメソッドは %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 テーブル
Table with 4 rows of data. RowID (values 1, 2, 3 ,4),  Name, Age, State (values CA, NY), and Job fields with data.

このテーブルの各行には、システムにより RowID 番号 (増加する整数値) が割り当てられます。ビットマップ・インデックスは、一連のビット文字列 (1 または 0 を含む文字列) を使用します。ビット文字列では、ビットの順序の位置がインデックス付きテーブルの RowID に対応します。上記のテーブルで State が “NY” である場合を例にとると、ビット文字列の “NY” を含む行に対応する各位置には 1 が、その他の位置には 0 が入ります。

例えば、State のビットマップ・インデックスは以下のとおりです。

State ビットマップ・インデックス
Bitmap boolean table: row for each State (values CA, NY, WY), column for each RowID, 1 if RowID has State value. 0 if not.

また、Age は以下のようになります。

Age ビットマップ・インデックス
Bitmap boolean table: row for each Age (values 24, 35, 48), column for each RowID, 1 if RowID has Age value. 0 if not.
Note:

ここで示す Age フィールドは、通常のデータ・フィールドにすることも、値を確実に派生できるフィールド (Calculated および SQLComputed) にすることもできます。

通常の演算にビットマップ・インデックスを使用する方法とは別に、SQL エンジンは、複数インデックスの結合を使用した特別なセットベースの演算を、ビットマップ・インデックスを使用して効率的に実行できます。例えば、ニューヨークに住む 24 歳以上に当てはまる Person のすべてのインスタンスを得るために、SQL エンジンは Age と State の論理 AND を実行します。

複数のインデックスの使用
AND on 2 bitmap rows: State=NY  RowID booleans AND Age=24  RowID booleans. Result: RowID boolean 1 if  both NY and 24.

結果として得られたビットマップには、検索基準に当てはまるすべての行のセットが含まれます。SQL エンジンは、これを使用して行からデータを返します。

SQL エンジンは、ビットマップ・インデックスを以下の演算に使用できます。

  • 任意のテーブルの複数の条件について AND を実行

  • 任意のテーブルの複数の条件について OR を実行

  • 任意のテーブルの RANGE 条件

  • 任意のテーブルの COUNT 演算

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) と呼ばれます。

こういったテーブルでビットマップ・インデックスを使用できるようにするには以下の手順に従います。

  1. %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 ];
    }
  2. 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 ];
    }
  3. 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 ];
    }
  4. 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 ];
    }
  5. %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 = bitmapextent = 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 プロパティを作成する必要があります。

  • 整数以外のフィールドを一意の ID キーとして使用している。

  • 複数フィールドの ID キーを使用している。

  • 親子リレーションシップ内の子テーブルである。

$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 である行を記録します。これは、以下の演算のパフォーマンスを大幅に向上させることができる非常に特殊なタイプのインデックスです。

  • SUMCOUNT、または AVG 集約計算(ビットスライス・インデックスは COUNT(*) 計算には使用できません)。ビットスライス・インデックスは、その他の集約関数には使用されません。

  • TOP n ... で指定されたフィールド。ORDER BY field 演算。

  • WHERE field > nWHERE 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 操作のパフォーマンスに影響を及ぼすことがあります。INSERTUPDATE、または DELETE 操作を使用してビットスライス・インデックスを生成および維持すると、ビットマップ・インデックスや通常のインデックスを使用する場合よりも速度が遅くなります。複数のビットスライス・インデックスを維持したり、頻繁に更新されるフィールドでビットスライス・インデックスを維持すると、パフォーマンス・コストが増える可能性があります。

揮発性のテーブル (多数の INSERT 操作、UPDATE 操作および DELETE 操作が実行されるもの) では、ビットスライス・インデックス用のストレージは徐々に効率が低下する可能性があります。%SYS.Maint.BitmapOpens in a new tab ユーティリティ・メソッドは、ビットマップ・インデックスとビットスライス・インデックスの両方を圧縮して、元の高い効率を復元します。詳細は、"ビットマップ・インデックスの維持" を参照してください。

列指向インデックス

列指向インデックスは、頻繁にクエリされるものの、テーブルに基盤となる行ストレージ構造があるフィールドに使用します。既定では、テーブルのそれぞれの行が $LIST として別々のグローバル添え字で格納されます。列指向インデックスには、特定のフィールドのデータが圧縮ベクトル化形式で保存されます。

InterSystems SQL DDL を使用して列指向インデックスを定義するには、次のように CREATE INDEXCREATE 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 コマンドを使用することです。インデックスの構築は、以下を実行します。

  1. 現在のインデックスの内容を削除します。

  2. メインのテーブルをスキャンし (各行を読み取り)、テーブルの各行にインデックスのエントリを追加します。必要に応じ、$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 インデックスのみを構築しています。

管理ポータルによるインデックスの構築

テーブルに既存のインデックスを構築 (インデックスを再構築) するには、以下の操作を実行します。

  1. 管理ポータルで、[システムエクスプローラ][SQL] の順に選択します。ページ上部の [切り替え] オプションを使ってネームスペースを選択します。利用可能なネームスペースのリストが表示されます。ネームスペースの選択後に、画面の左側にある [スキーマ] ドロップダウン・リストを選択します。これには、現在のネームスペースのスキーマのリストと、各スキーマに関連付けられているテーブルまたはビューがあるかどうかを示すブーリアン・フラグが表示されます。

  2. このリストからスキーマを選択すると、[スキーマ] ボックスに表示されます。上記と同様に、ドロップダウン・リストでは、テーブル、システム・テーブル、ビュー、プロシージャ、またはスキーマに属するすべてを選択できます。[テーブル] または [すべて] を選択し、[テーブル] フォルダを開いて、このスキーマのテーブルのリストを開きます。テーブルがない場合は、フォルダを開くと空白ページが表示されます([テーブル] または [すべて] を選択しない場合は、[テーブル] フォルダを開くとネームスペース全体のテーブルがリストされます)。

  3. 一覧表示されているテーブルのいずれかを選択します。これにより、テーブルの [カタログの詳細] が表示されます。

    • すべてのインデックスを再構築する場合 : [アクション] ドロップダウン・リストをクリックし、 [テーブルのインデックスを再構築] を選択します。

    • 1 つのインデックスを再構築する場合 : [インデックス] ボタンをクリックして、既存のインデックスを表示します。リストの各インデックスに、[インデックス再構築] のオプションがあります。

Caution:

他のユーザがテーブルのデータにアクセスしている間は、この方法でインデックスを再構築しないでください。アクティブ・システム上でインデックスを再構築するには、BUILD INDEX を使用するか、プログラムによる方法を使用します。

プログラミングによるインデックスの構築

インデックスを作成するテーブルに %PersistentOpens in a new tab クラスによって用意されている %BuildIndices() メソッドと %BuildIndicesAsync() メソッドを使用することもできます。これらのメソッドは、InterSystems IRIS の既定のストレージ構造を使用しているクラス向けにのみ提供されています。これらのメソッドを呼び出すには、指定のクラスにインデックス定義を 1 つ以上追加してコンパイルしておく必要があります。メソッドの詳細は、以下のリンクからクラスリファレンスのページを参照してください。

  • %Library.Persistent.%BuildIndices()Opens in a new tab%BuildIndices() はバックグラウンド・プロセスとして実行されますが、呼び出し元に制御が戻るには、%BuildIndices() が完了するまで待機する必要があります。

  • %Library.Persistent.%BuildIndicesAsync()Opens in a new tab%BuildIndicesAsync()%BuildIndices() をバックグラウンド・プロセスとして開始し、すぐに呼び出し元に制御が戻ります。%BuildIndicesAsync() の最初の引数は、queueToken 出力引数です。その他の引数は、%BuildIndices() と同じです。

インデックスの検証

以下のメソッドのいずれかを使用して、インデックスを検証できます。

両方のメソッドは、指定されたテーブルの 1 つまたは複数のインデックスのデータ整合性を確認するほか、必要に応じて、検出されたインデックス整合性の問題を修正します。インデックス検証は、以下の 2 つの手順で実行されます。

  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() 配列で返されます。

クエリ処理でのインデックスの使用

インデックスは、頻繁に要求されるデータのサブセットをソートして管理することで、クエリを最適化するメカニズムを提供します。どのフィールドにインデックスを定義するかを決定する際にも注意が必要です。インデックスが少なすぎる場合やインデックスに誤りがある場合は主要なクエリの速度が大きく低下します。また、インデックスが多すぎる場合は、INSERTUPDATE のパフォーマンスが低下します (インデックス値の設定や更新が必要になるため)。

インデックスの対象

インデックスの追加によってクエリのパフォーマンスが向上するかどうかを判断するには、管理ポータルの 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" コマンドと、このドキュメントの “インデックスの定義と構築” の章を参照してください。

インデックス構成オプション

以下のシステム全体の構成メソッドは、クエリでインデックスの使用を最適化するために使用できます。

  • 主キーを IDKey インデックスとして使用するには、$SYSTEM.SQL.Util.SetOption()Opens in a new tab メソッドを SET status=$SYSTEM.SQL.Util.SetOption("DDLPKeyNotIDKey",0,.oldval) のように設定します。既定値は 1 です。

  • SELECT DISTINCT クエリでインデックスを使用するには、$SYSTEM.SQL.Util.SetOption()Opens in a new tab メソッドを SET status=$SYSTEM.SQL.Util.SetOption("FastDistinct",1,.oldval) のように設定します。既定値は 1 です。

詳細は、"システム管理ガイド" にリストされている "SQL およびオブジェクトの設定ページ" を参照してください。

%ALLINDEX、%IGNOREINDEX、%NOINDEX の使用法

FROM 節では、%ALLINDEX%IGNOREINDEXoptimize-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 つあります。

インデックス分析

以下のいずれかを使用して、管理ポータルから SQL クエリのインデックス使用を分析できます。

  • [システムエクスプローラ][ツール] [SQL パフォーマンス・ツール] [インデックス分析] の順に選択します。

  • [システムエクスプローラ][SQL] の順に選択し、[ツール] ドロップダウン・メニューから [インデックス分析] を選択します。

[インデックス分析] には、現在のネームスペースの SQL 文カウントが表示され、5 つのインデックス分析レポート・オプションが用意されています。

SQL 文カウント

[SQL インデックス・アナライザ] の上部には、ネームスペースに含まれるすべての SQL 文をカウントするオプションがあります。[SQL 文の収集] ボタンをクリックします。 [SQL インデックス・アナライザ] では、カウントの処理中には “SQL 文の収集中 ....” と表示され、カウントが完了すると “完了!” と表示されます。SQL 文は、クエリ・キャッシュのカウント、クラス・メソッドのカウント、およびクラス・クエリのカウントという 3 つのカテゴリでカウントされます。これらのカウントは、現在のネームスペース全体に対するものであり、[スキーマ選択] オプションの影響を受けません。対応するメソッドは、%SYS.PTools.UtilSQLAnalysisOpens in a new tab クラスの getSQLStmts()Opens in a new tab です。

[ステートメントを削除] ボタンを使用して、現在のネームスペース内の収集されたすべての文を削除できます。このボタンにより、clearSQLStatements()Opens in a new tab メソッドが呼び出されます。

レポート・オプション

現在のネームスペース内の選択済みスキーマのクエリ・キャッシュのレポートを確認するか、(スキーマが選択されていない場合) 現在のネームスペース内のすべてのクエリ・キャッシュのレポートを確認できます。システム・クラス・クエリ、INSERT 文、IDKEY インデックスを、この分析から除外することも、この分析の対象にすることもできます。スキーマ選択およびスキップ・オプションのチェック・ボックスは、ユーザによってカスタマイズされます。

インデックス分析レポート・オプションを以下に示します。

  • インデックス使用 : このオプションは、現在のネームスペース内のすべてのクエリ・キャッシュを取得し、それぞれにプラン表示を生成します。さらに、各インデックスが各クエリで使用された回数とネームスペース内のすべてのクエリによる各インデックスの合計使用量のカウントを保持します。これを使用して、使用されていないインデックスを明らかにし、削除したり役立つように変更することができます。結果セットは、最少使用のインデックスから最多使用のインデックスに向けて順序付けされます。

  • テーブル・スキャンを行うクエリ : このオプションは、テーブル・スキャンを実行する、現在のネームスペース内のすべてのクエリを識別します。可能な限り、テーブル・スキャンは回避する必要があります。テーブル・スキャンを必ず防ぐことはできませんが、テーブルで多数のテーブル・スキャンが発生する場合は、テーブルに定義されているインデックスを確認する必要があります。多くの場合、テーブル・スキャンのリストと一時インデックスのリストは重複しています。一方を固定して、もう一方を削除します。結果セットでは、最大ブロック・カウントから最小ブロック・カウントの順にテーブルがリストされます。[プラン表示] リンクにより、[文テキストとクエリ・プラン] が表示されます。

  • 一時インデックスを使用するクエリ : このオプションは、SQL を解決するための一時インデックスを構築する、現在のネームスペース内のすべてのクエリを識別します。場合によっては、一時インデックスの使用が役立ち、パフォーマンスが向上します。例えば、InterSystems IRIS でマスタ・マップを順序どおりに読み込むために使用できる、範囲条件に基づく小さなインデックスを構築します。一時インデックスは別のインデックスの単純なサブセットとして非常に効率が良い場合があります。また、一時インデックスがパフォーマンスの低下につながることもあります。例えば、条件を含むプロパティに対する一時インデックスを構築するために、マスタ・マップをスキャンする場合です。この状況は、必要なインデックスが見つからないことを意味します。インデックスは、一時インデックスと一致するクラスに追加する必要があります。結果セットでは、最大ブロック・カウントから最小ブロック・カウントの順にテーブルがリストされます。[プラン表示] リンクにより、[文テキストとクエリ・プラン] が表示されます。

  • JOIN のインデックスがないクエリ : このオプションは、現在のネームスペース内で結合が含まれるすべてのクエリを検証し、その結合をサポートするために定義されたインデックスがあるかどうかを確認します。結合のサポートに利用できるインデックスはランク付けされます。このランクは、0 (インデックスが存在しない) から 4 (結合を完全にサポートするインデックス) までの範囲になります。外部結合では、1 方向のインデックスが必要です。内部結合では、双方向のインデックスが必要です。既定では、結果セットには、JoinIndexFlag < 4 がある行のみが含まれます。JoinIndexFlag=4 は、結合を完全にサポートするインデックスがあることを意味します。

  • 外れ値インデックスを使用したクエリ : このオプションは、現在のネームスペース内で異常値が含まれるすべてのクエリを識別し、その異常値をサポートするために定義されたインデックスがあるかどうかを確認します。異常値のサポートに利用できるインデックスはランク付けされます。このランクは、0 (インデックスが存在しない) から 4 (異常値を完全にサポートするインデックス) までの範囲になります。既定では、結果セットには、OutlierIndexFlag < 4 がある行のみが含まれます。OutlierIndexFlag=4 は、異常値を完全にサポートするインデックスがあることを意味します。

これらのオプションのいずれかを選択すると、自動的に操作が実行されて、結果が表示されます。オプションを最初に選択したとき、または対応するメソッドを最初に呼び出したときに、結果データが生成されます。そのオプションを再度選択しても、そのメソッドを再度呼び出しても、InterSystems IRIS は同じ結果を再表示します。新しい結果データを生成するには、 [SQL 文の収集] ボタンを使用して、インデックス・アナライザの結果テーブルを再初期化する必要があります。[次で始まるすべてのシステムクラスとルーチンをスキップ] または [ループロジックがないため、INSERT ステートメントをスキップ] チェック・ボックス・オプションを変更しても、インデックス・アナライザの結果テーブルを再初期化できます。%SYS.PTools.UtilSQLAnalysisOpens in a new tab のメソッドの新しい結果データを生成するには、getSQLStmts()Opens in a new tab を呼び出して、インデックス・アナライザの結果テーブルを再初期化する必要があります。

インデックスのリスト表示

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 が含まれます。

このメソッドは、以下を除くすべてのインデックスの値を返します。

  • ビットマップ・インデックス、またはビットマップ・エクステント・インデックス。

  • インデックスに (ELEMENTS) 式または (KEYS) 式が含まれている場合。そのようなインデックスの詳細は、“コレクションのインデックス作成” のセクションを参照してください。

インスタンスの削除

indexnameDelete() メソッド (indexname はインデックスの名前) は、Unique、PrimaryKey、IdKey の各インデックスに使用します。このメソッドは、指定されたキーのプロパティ/列の値に一致するインスタンスを削除します。オプションの引数が 1 つあり、これを指定して操作の並行処理を指定できます。このメソッドは %Status コードを返します。%Compiler.Type.Index.Delete() メソッドとして実装されます。

FeedbackOpens in a new tab