永続オブジェクトとストレージのグローバル
永続クラスを使用することで、オブジェクトをデータベースに保存した後、オブジェクトとして取得することも、SQL を使用して取得することも可能になります。どのようにアクセスするかにかかわらず、これらのオブジェクトはグローバルに格納されます。グローバルは永続多次元配列と考えることができます。
ここでは、グローバル名がどのように決定されるか、およびそれらをどのように制御できるかについて説明します。説明のために、グローバルの内容についても見ていきます。データの整合性を確保するには、オブジェクトまたは SQL を介してデータにアクセスするのが最良の方法です。
このページでは、他の 2 つのバリエーションも紹介します。
-
列指向ストレージ。一部のシナリオではパフォーマンス上のメリットがあります。列指向ストレージについては、"SQL テーブルのストレージ・レイアウトの選択" でも詳しく説明しています。
標準のグローバル名
永続クラスの場合、クラス定義を作成してコンパイルすると、クラス名に基づいてクラスのグローバル名が生成されます。
例えば、以下のように GlobalsTest.President クラスを定義するとします。
Class GlobalsTest.President Extends %Persistent
{
/// President's name (last,first)
Property Name As %String(PATTERN="1U.L1"",""1U.L");
/// Year of birth
Property BirthYear As %Integer;
/// Short biography
Property Bio As %Stream.GlobalCharacter;
/// Index for Name
Index NameIndex On Name;
/// Index for BirthYear
Index DOBIndex On BirthYear;
}
クラスのコンパイル後に、クラスの下部に以下のようなストレージ定義が生成されることを確認できます。
Storage Default
{
<Data name="PresidentDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>BirthYear</Value>
</Value>
<Value name="4">
<Value>Bio</Value>
</Value>
</Data>
<DataLocation>^GlobalsTest.PresidentD</DataLocation>
<DefaultData>PresidentDefaultData</DefaultData>
<IdLocation>^GlobalsTest.PresidentD</IdLocation>
<IndexLocation>^GlobalsTest.PresidentI</IndexLocation>
<StreamLocation>^GlobalsTest.PresidentS</StreamLocation>
<Type>%Storage.Persistent</Type>
}
特に、次のストレージ・キーワードに着目してください。
-
DataLocation は、クラス・データが格納されるグローバルです。このグローバルの名前は、"D" が追加された完全なクラス名 (パッケージ名を含む) で、ここでは、^GlobalsTest.PresidentD となっています。
-
IdLocation (DataLocation と同じである場合が多い) は、ID カウンタが格納されるグローバルで、ルートにあります。
-
IndexLocation は、クラスのインデックスが格納されるグローバルです。このグローバルの名前は、"I" が追加された完全なクラス名で、^GlobalsTest.PresidentI となっています。
-
StreamLocation は、あらゆるストリーム・プロパティが格納されるグローバルです。このグローバルの名前は、"S" が追加された完全なクラス名で、^GlobalsTest.PresidentS となっています。
クラスのオブジェクトをいくつか作成して保存した後は、ターミナルでこれらのグローバルのコンテンツを確認できます。
USER>zwrite ^GlobalsTest.PresidentD
^GlobalsTest.PresidentD=3
^GlobalsTest.PresidentD(1)=$lb("",1732,"1","Washington,George")
^GlobalsTest.PresidentD(2)=$lb("",1735,"2","Adams,John")
^GlobalsTest.PresidentD(3)=$lb("",1743,"3","Jefferson,Thomas")
USER>zwrite ^GlobalsTest.PresidentI
^GlobalsTest.PresidentI("DOBIndex",1732,1)=""
^GlobalsTest.PresidentI("DOBIndex",1735,2)=""
^GlobalsTest.PresidentI("DOBIndex",1743,3)=""
^GlobalsTest.PresidentI("NameIndex"," ADAMS,JOHN",2)=""
^GlobalsTest.PresidentI("NameIndex"," JEFFERSON,THOMAS",3)=""
^GlobalsTest.PresidentI("NameIndex"," WASHINGTON,GEORGE",1)=""
USER>zwrite ^GlobalsTest.PresidentS
^GlobalsTest.PresidentS=3
^GlobalsTest.PresidentS(1)="1,239"
^GlobalsTest.PresidentS(1,1)="George Washington was born to a moderately prosperous family of planters in colonial ..."
^GlobalsTest.PresidentS(2)="1,195"
^GlobalsTest.PresidentS(2,1)="John Adams was born in Braintree, Massachusetts, and entered Harvard College at age 1..."
^GlobalsTest.PresidentS(3)="1,202"
^GlobalsTest.PresidentS(3,1)="Thomas Jefferson was born in the colony of Virginia and attended the College of Willi..."
^GlobalsTest.PresidentD の添え字は IDKey です。いずれのインデックスも IDKey としては定義していないため、ID が IDKey として使用されます。ID の詳細は、"ID の生成を制御する方法" を参照してください。
^GlobalsTest.PresidentI の最初の添え字はインデックスの名前です。
^GlobalsTest.PresidentS の最初の添え字は、大統領の ID ではなく、略歴エントリの ID です。
これらのグローバルは、管理ポータルでも確認できます ([システムエクスプローラ]→[グローバル])。
グローバル名では最初の 31 文字だけが重要であるため、完全なクラス名がきわめて長い場合は、^package1.pC347.VeryLongCla4F4AD のようなグローバル名が生成される場合があります。クラスのすべてのグローバル名が必ず一意になるように、このような名前が生成されます。クラスのグローバルで直接作業する場合、ストレージ定義を調べて、グローバルの実際の名前を確認してください。または、クラス定義内で DEFAULTGLOBAL パラメータを使用して、グローバル名を制御できます。"ユーザ定義のグローバル名" を参照してください。
ハッシュ化したグローバル名
USEEXTENTSET パラメータを値 1 に設定している場合、短いグローバル名が生成されます (このパラメータの既定値は 0、つまり標準のグローバル名の使用です)。こういった短いグローバル名は、パッケージ名のハッシュとクラス名のハッシュから作成され、後ろに接尾辞が付きます。標準の名前の方が読みやすいですが、短い名前の方がパフォーマンスの向上につながる可能性があります。
USEEXTENTSET を 1 に設定した場合、各インデックスも個別のグローバルに割り当てられます。最初の添え字が異なる単一のインデックス・グローバルは使用されません。繰り返しますが、これはパフォーマンス向上のために行われます。
前述の箇所で定義した GlobalsTest.President クラスにハッシュ化したグローバル名を使用するには、クラス定義に以下を追加します。
/// Use hashed global names
Parameter USEEXTENTSET = 1;
データを削除し、ストレージ定義を削除し、クラスをリコンパイルした後に、ハッシュ化されたグローバル名が含まれる以下のような新しいストレージ定義を確認できます。
Storage Default
{
...
<DataLocation>^Ebnm.EKUy.1</DataLocation>
<DefaultData>PresidentDefaultData</DefaultData>
<ExtentLocation>^Ebnm.EKUy</ExtentLocation>
<IdLocation>^Ebnm.EKUy.1</IdLocation>
<Index name="DOBIndex">
<Location>^Ebnm.EKUy.2</Location>
</Index>
<Index name="IDKEY">
<Location>^Ebnm.EKUy.1</Location>
</Index>
<Index name="NameIndex">
<Location>^Ebnm.EKUy.3</Location>
</Index>
<IndexLocation>^Ebnm.EKUy.I</IndexLocation>
<StreamLocation>^Ebnm.EKUy.S</StreamLocation>
<Type>%Storage.Persistent</Type>
}
特に、次のストレージ・キーワードに着目してください。
-
ExtentLocation は、このクラスのグローバル名の計算に使用されるハッシュ値です (ここでは ^Ebnm.EKUy)。
-
クラス・データが格納される DataLocation (IDKEY インデックスと等しい) は、名前に “.1” が付いたハッシュ値になっています (ここでは ^Ebnm.EKUy.1)。
-
各インデックスに固有の Location が指定されるため、各インデックスのグローバルも固有になります。IdKey インデックス・グローバルの名前は、名前に ”.1” が付いたハッシュ値と等しいです。この例では、^Ebnm.EKUy.1 です。これ以外のインデックスのグローバルでは、名前に “.2” から “.N” が付けられます。ここでは、DOBIndex はグローバル ^Ebnm.EKUy.2 に格納され、NameIndex は ^Ebnm.EKUy.3 に格納されます。
-
IndexLocation は、名前に “.I” が付いたハッシュ値、つまり ^Ebnm.EKUy.I ですが、このグローバルは多くの場合使用されません。
-
StreamLocation は、名前に “.S” が付いたハッシュ値、つまり ^Ebnm.EKUy.S です。
オブジェクトをいくつか作成して保存した後、これらのグローバルのコンテンツは以下のようになります (ここでもターミナルを使用して確認します)。
USER>zwrite ^Ebnm.EKUy.1
^Ebnm.EKUy.1=3
^Ebnm.EKUy.1(1)=$lb("","Washington,George",1732,"1")
^Ebnm.EKUy.1(2)=$lb("","Adams,John",1735,"2")
^Ebnm.EKUy.1(3)=$lb("","Jefferson,Thomas",1743,"3")
USER>zwrite ^Ebnm.EKUy.2
^Ebnm.EKUy.2(1732,1)=""
^Ebnm.EKUy.2(1735,2)=""
^Ebnm.EKUy.2(1743,3)=""
USER>zwrite ^Ebnm.EKUy.3
^Ebnm.EKUy.3(" ADAMS,JOHN",2)=""
^Ebnm.EKUy.3(" JEFFERSON,THOMAS",3)=""
^Ebnm.EKUy.3(" WASHINGTON,GEORGE",1)=""
USER>zwrite ^Ebnm.EKUy.S
^Ebnm.EKUy.S=3
^Ebnm.EKUy.S(1)="1,239"
^Ebnm.EKUy.S(1,1)="George Washington was born to a moderately prosperous family of planters in colonial ..."
^Ebnm.EKUy.S(2)="1,195"
^Ebnm.EKUy.S(2,1)="John Adams was born in Braintree, Massachusetts, and entered Harvard College at age 1..."
^Ebnm.EKUy.S(3)="1,202"
^Ebnm.EKUy.S(3,1)="Thomas Jefferson was born in the colony of Virginia and attended the College of Willi..."
SQL 文 CREATE TABLE を使用して定義したクラスの場合、USEEXTENTSET パラメータの既定値は 1 です。テーブルの作成の詳細は、"テーブルの定義" を参照してください。
例えば、管理ポータルを使用してテーブルを作成してみます ([システムエクスプローラ]→[SQL]→[クエリ実行])。
CREATE TABLE GlobalsTest.State (NAME CHAR (30) NOT NULL, ADMITYEAR INT)
テーブルにいくつかのデータを入力した後、管理ポータル ([システムエクスプローラ]→[グローバル]) でグローバル ^Ebnm.BndZ.1 および ^Ebnm.BndZ.2 を確認します。パッケージ名は GlobalsTest のままなので、GlobalsTest.State のグローバル名の最初のセグメントは、GlobalsTest.President の場合と同じです。

ターミナルで、グローバルのコンテンツは以下のように表示されます。
USER>zwrite ^Ebnm.BndZ.1
^Ebnm.BndZ.1=3
^Ebnm.BndZ.1(1)=$lb("Delaware",1787)
^Ebnm.BndZ.1(2)=$lb("Pennsylvania",1787)
^Ebnm.BndZ.1(3)=$lb("New Jersey",1787)
USER>zwrite ^Ebnm.BndZ.2
^Ebnm.BndZ.2(1)=$zwc(412,1,0)/*$bit(2..4)*/
グローバル ^Ebnm.BndZ.1 には州のデータ、^Ebnm.BndZ.2 にはビットマップ・エクステント・インデックスが格納されています。"ビットマップ・エクステント・インデックス" を参照してください。
SQL を使用して作成したクラスで標準のグローバル名を使用する場合、以下のように USEEXTENTSET パラメータを 0 に設定できます。
CREATE TABLE GlobalsTest.State (%CLASSPARAMETER USEEXTENTSET 0, NAME CHAR (30) NOT NULL, ADMITYEAR INT)
これによって、標準のグローバル名 ^GlobalsTest.StateD および ^GlobalsTest.StateI が生成されます。
コマンド do $SYSTEM.SQL.SetDDLUseExtentSet(0, .oldval) を実行することによって、CREATE TABLE 文によって作成されたクラスについて USEEXTENTSET パラメータに使用される既定値を 0 に変更することができます。以前の既定値は oldval で返されます。
XEP を使用して作成したクラスの場合、USEEXTENTSET パラメータの既定値は 1 で、これを変更することはできません。XEP の詳細は、"InterSystems XEP による Java オブジェクトの永続化" を参照してください。
ユーザ定義のグローバル名
クラスのグローバル名をより詳細に制御するには、DEFAULTGLOBAL パラメータを使用します。このパラメータは、USEEXTENTSET パラメータと共に機能して、グローバル名前付け方式を決定します。
例えば以下のように、DEFAULTGLOBAL パラメータを追加して、GlobalsTest.President クラスのグローバル名のルートを ^GT.Pres に設定してみます。
/// Use hashed global names
Parameter USEEXTENTSET = 1;
/// Set the root of the global names
Parameter DEFAULTGLOBAL = "^GT.Pres";
データを削除し、ストレージ定義を削除し、クラスをリコンパイルした後に、以下のようなグローバル名を確認できます。
Storage Default
{
...
<DataLocation>^GT.Pres.1</DataLocation>
<DefaultData>PresidentDefaultData</DefaultData>
<ExtentLocation>^GT.Pres</ExtentLocation>
<IdLocation>^GT.Pres.1</IdLocation>
<Index name="DOBIndex">
<Location>^GT.Pres.2</Location>
</Index>
<Index name="IDKEY">
<Location>^GT.Pres.1</Location>
</Index>
<Index name="NameIndex">
<Location>^GT.Pres.3</Location>
</Index>
<IndexLocation>^GT.Pres.I</IndexLocation>
<StreamLocation>^GT.Pres.S</StreamLocation>
<Type>%Storage.Persistent</Type>
}
同様に、DEFAULTGLOBAL パラメータは、SQL を使用したクラスの定義にも使用できます。
CREATE TABLE GlobalsTest.State (%CLASSPARAMETER USEEXTENTSET 0, %CLASSPARAMETER DEFAULTGLOBAL = '^GT.State',
NAME CHAR (30) NOT NULL, ADMITYEAR INT)
これによって、グローバル名 ^GT.StateD および ^GT.StateI が生成されます。
グローバル名の再定義
既存のグローバル名を再定義する方法 (例えば、USEEXTENTSET パラメータまたは DEFAULTGLOBAL パラメータの値の変更) でクラス定義を編集する場合、既存のストレージ定義を削除して、コンパイラで新しいストレージ定義を生成できるようにする必要があります。既存のグローバル内のデータはすべて保持されます。保持されるデータをすべて新しいグローバル構造に移行する必要があります。
詳細は、"データを格納した永続クラスの再定義" を参照してください。
列指向ストレージの使用法
InterSystems IRIS でデータを保存する永続クラスを使用する場合、通常はデータが行単位で保存されます。このストレージ・レイアウトは、データの挿入、更新、削除が頻繁に発生するオンライン・トランザクション処理に適しています。一方、オンライン分析処理の場合は、データを列単位で保存する方が適しています。このような処理ではデータベース全体で特定列のデータを集約しますが、リアルタイムの挿入、更新、削除の頻度は高くありません。例えば、行ストレージを使用している場合、指定したプロパティのすべての値の平均値を計算するには、そのデータベースにあるすべての行を読み込む必要があります。列指向ストレージは、そのプロパティの値を収めた列のみを読み込むようにすることで、計算を高速化します。
クラスに列指向ストレージを使用するには、以下を行います。
-
STORAGEDEFAULT クラス・パラメータを "columnar" として指定します。
Parameter STORAGEDEFAULT = "columnar";
-
同じクラスに対して、Final クラス・キーワードまたは NoExtent クラス・キーワードを指定します。また、そのクラスに直下のサブクラスがあれば、それを明示的に Final として定義する必要があります。
サンプル・クラスにこれらの変更を加え、そのクラスのデータを削除し、そのクラスのストレージ定義を削除してからリコンパイルすると、結果として得られるストレージ定義は次のようになります。
トランザクションベースの処理を使用していても、頻繁に分析クエリの実行対象となるプロパティがわずかな場合は、そのプロパティにのみ列指向ストレージを使用できます。クラスで単一のプロパティに列指向ストレージを使用するには、STORAGEDEFAULT プロパティ・パラメータを "columnar" として指定します。
Property Amount As %Numeric(STORAGEDEFAULT = "columnar");
あるクラスに行ストレージを使用して、頻繁にクエリの対象となるプロパティに列指向インデックスを作成することもできます。
クラスの特定のプロパティに列指向インデックスを作成するには、そのインデックスにキーワード type = columnar を使用します。
Class Sample.BankTransaction Extends %Persistent [ DdlAllowed ]
{
/// Line below is optional
Parameter STORAGEDEFAULT = "row";
Property Amount As %Numeric(SCALE = 2);
Index AmountIndex On Amount [ type = columnar ];
//other class members...
}
インデックスの詳細は、"インデックスの追加" を参照してください。
列指向ストレージの詳細は、"SQL テーブルのストレージ・レイアウトの選択" を参照してください。
プロパティに個別のグローバルを使用
リリース 2024.3 以降、リテラル・プロパティを独自のグローバルに格納できるようになりました。このオプションは、%VectorOpens in a new tab とそのサブクラスでは既定です。他のリテラル・プロパティの場合、プロパティを独自のグローバルに格納するには、STORAGEDEFAULT プロパティ・パラメータを globalnode として指定します。
大量のデータを保持する他のリテラル・プロパティには、このオプションの使用を検討します。以下に例を示します。
Property MyLongString as %String (MAXLEN="",STORAGEDEFAULT="globalnode");
%VectorOpens in a new tab タイプまたはサブクラスのプロパティについては、STORAGEDEFAULT プロパティ・パラメータを別の値に設定することで、既定の動作をオーバーライドできます。
Property MyVector as %Vector (STORAGEDEFAULT="row");