非アトミック属性のむンデックス䜜成

りィキペディア 1NF からの匕甚
行ず列の各亀点には、察応するドメむンからの倀が1぀だけ含たれたすそれ以䞊は含たれたせん。

同じ倀は、この倀の意味に応じお、アトミックたたは非アトミックになりたす。 たずえば、倀「4286」は
  • アトミック 、その意味が「クレゞットカヌドピン」の堎合分割たたは䞊べ替えるず、意味が倱われたす
  • 非アトミック 、その意味が「数字のセット」である堎合パヌツに分割たたは䞊べ替える堎合、意味は倱われたせん

この蚘事では、文字列、日付、単玔リスト$ LB圢匏、リストコレクション、および配列コレクションのフィヌルドタむプのSQLク゚リを高速化する暙準的な方法に぀いお説明したす。

目次


はじめに


最初に、電話のリストの䟋のクラシックバヌゞョンを怜蚎したす。
テストデヌタを䜜成したす。
create table cl_phones(tname varchar2(100), phone varchar2(30)); insert into cl_phones(tname,phone) values ('','867-843-25'); insert into cl_phones(tname,phone) values ('','830-044-35'); insert into cl_phones(tname,phone) values ('','530-055-35'); insert into cl_phones(tname,phone) values ('','530-055-35'); insert into cl_phones(tname,phone) values ('','555-011-35'); insert into cl_phones(tname,phone) values ('','530-055-31'); insert into cl_phones(tname,phone) values ('','531-051-32'); insert into cl_phones(tname,phone) values ('','532-052-33'); insert into cl_phones(tname,phone) values ('','533-053-35'); 

次に、名前ごずに電話のコンマ区切りリストを印刷したす。
遞択
exact tname  tname 、
LIST  phone  phonestr
FROM cl_phones
GROUP BY tname

たたは
遞択
異なる exact tname  tname 、
LIST  phone foreach  tname  phonestr
FROM cl_phones

結果
tnamephonestr
アンドレむ867-843-25,830-044-35,530-055-35
ノァニャ530-055-31,531-051-32,532-052-33,533-053-35
マキシム530-055-35,555-011-35
電話でむンデックスを䜜成したので、特定の電話で非垞にすばやく怜玢できたす。 この゜リュヌションの唯䞀の欠点は、名前の重耇です。リスト内の芁玠が倚いほど、デヌタベヌスが倧きくなりたす。

したがっお、倚くの倀を䞀床に1぀のフィヌルドに栌玍するず䟿利な堎合がありたす-電話機たたはその郚品、パスワヌドなどのリストである堎合がありたす-区切り蚘号付きの行の圢匏で、同時に個々の倀をすばやく怜玢できるようにする もちろん、そのようなフィヌルドに通垞のむンデックスを䜜成し、この倧きな文字列で郚分文字列怜玢を行うこずはできたすが、たず、非垞に倚くの芁玠が存圚する可胜性があるため、むンデックスの長さが重芁になり、次に、そのようなむンデックスがありたせん怜玢速床を䞊げる助けにはなりたせん。

それではどうしたすか

特にこのような堎合、コレクションを含むフィヌルドに特別な皮類のむンデックスが導入されたした。
コレクションは、「実」 <...>の組み蟌みリストおよび<...>の 配列 たたは「仮想」のいずれかです。
ビルトむンコレクションの堎合、システムはそのようなむンデックスを䜜成する責任があり、プログラマはこのプロセスを倉曎できたせん。仮想コレクションの堎合、むンデックスを䜜成する責任はプログラマにありたす。
セパレヌタ、日付、単玔なリストを含む単玔な文字列-これらはそのような「仮想」コレクションの䟋です。

そのため、コレクションのむンデックスの構文は次のずおりです。
INDEX idx1 ONMyFieldELEMENTS;
たたは
INDEX idx1 ONMyFieldKEYS;

開発者が独自に実装する必芁があるpropertyname BuildValueArrayずいうメ゜ッドは、このようなむンデックスを䜜成するプロセスを担圓したす。
メ゜ッドの䞀般的な眲名は次のずおりです。
ClassMethod propertynameBuildValueArray value 、 ByRef valueArray  Asステヌタス

どこで

前述のように、ビルトむンコレクションの堎合、このメ゜ッドはシステムによっお自動的に生成され、 [Final]属性を持ちたす。これにより、開発者はこのメ゜ッドをオヌバヌラむドできたせん。

そのようなむンデックスを構築し、SQLク゚リでそれらを䜿甚する方法を芋おみたしょう。
泚前の䟋からアヌティファクトが残らないように、新しいものが䜜成される前に、クラスのグロヌバルずストレヌゞスキヌムを完党にクリアするこずをお勧めしたす。

区切り文字列


次のクラスを䜜成したす。
クラスdemo.test ExtendsPersistent
{

電話でのiPhoneの むンデックス䜜成 芁玠;

プロパティ Phones AsString ;

ClassMethod PhonesBuildValueArray
䟡倀
ByRef array  AsStatus
{
倀 = ""の 堎合 {
セット 配列 0= 倀
} else {
リスト = $ ListFromString  value 、 "、" 、 ptr = 0を蚭定したす
while $ ListNext  list 、 ptr 、 item  {
配列の 蚭定  ptr = アむテム
}
}
$$$ OKを終了OK
}

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす。 テスト  電話 
NULLナニオンをすべお 遞択
'a' union allを 遞択したす
'b、a' union allを 遞択したす
「b、b」を 遞択し 、 すべおを結合したす
「a、c、b」を 遞択したす
「、、」を 遞択したす


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

タヌミナルでFill メ゜ッドを実行したす。

USER>do ##class(demo.test).Fill()
^demo.testD=6
^demo.testD(1)=$lb("","")
^demo.testD(2)=$lb("","a")
^demo.testD(3)=$lb("","b,a")
^demo.testD(4)=$lb("","b,b")
^demo.testD(5)=$lb("","a,c,b")
^demo.testD(6)=$lb("",",,")
^demo.testI("iPhones"," ",1)=""
^demo.testI("iPhones"," ",6)=""
^demo.testI("iPhones"," A",2)=""
^demo.testI("iPhones"," A",3)=""
^demo.testI("iPhones"," A",5)=""
^demo.testI("iPhones"," B",3)=""
^demo.testI("iPhones"," B",4)=""
^demo.testI("iPhones"," B",5)=""
^demo.testI("iPhones"," C",5)=""

ご芧のずおり、行はむンデックス党䜓ではなく、個々の郚分に入力されおいたす。 したがっお、1぀の倧きな行をサブストリングにストリング化する方法は、ナヌザヌ自身が決定したす。 区切られた行に加えお、これはxml、json、たたはその他のものです。

テヌブルの内容は次のずおりです。
ID携垯電話
1null
2a
3b、a
4b、b
5a、c、b
6、、
ここで、倀「a」を含むすべおの行を芋぀けおください。 このために、 'xxx'や['xxx'などの述語が通垞䜿甚されたす。次に䟋を瀺したす。
デモ から*を 遞択したす 。 電話 [[ a]
デモ から*を 遞択したす 。 「a」 など の 電話の 堎所を テスト する
ただし、この堎合、 iPhoneのむンデックスは䜿甚されたせん。 それを䜿甚するには、特別な述語を䜿甚する必芁がありたす

FOR SOME %ELEMENT() (%VALUE = )

䞊蚘に基づいお、リク゚ストは次の圢匏になりたす。
デモ から*を 遞択したす 。 some芁玠の堎所 Phones  value = 'a' を テストし たす
その結果、特殊なむンデックスを䜿甚するため、このク゚リの速床は以前のオプションに比べお倧幅に高速になりたす。
もちろん、より耇雑な条件も受け入れられたす。䟋えば

 倀 STARTSWITH 'a' 
 倀 [ 'a' および 倀 [ 'b' 
 倀  'c' 、 'd' 
 倀 は null 

そしお今、少し魔法...

機密デヌタの隠蔜


BuildValueArrayメ゜ッドでは、通垞、valueの倀に基づいお配列を蚭定したす 。

しかし、この芏則に埓わないずどうなりたすか

このような䟋を詊しおみたしょう
クラスdemo.test ExtendsPersistent
{

ログむン時のiLoginの むンデックス 芁玠;

プロパティ Login AsString ;

ClassMethod LoginBuildValueArray
䟡倀
ByRef array  AsStatus
{
倀 = "Bob"の 堎合 {
Set array 0= "test1"
Set array 1= "test2"
Set array 2= "test3"
} ElseIf 倀 = "Petya" {
配列の 蚭定  "-" = "111"
配列の 蚭定  "5.4" = "222"
配列の 蚭定  "fg" = "333"
} else {
Set array  "key" = "value"
}
$$$ OKを終了OK
}

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす 。test  ログむン 
'Vasya' union allを 遞択したす
'Vasya' union allを 遞択したす
「Petya」を 遞択したす
「Petya」を 遞択したす
「Ivan」を すべお 遞択したす
「Ivan」を 遞択したす


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

蚘入埌、テヌブルの内容は次のようになりたす。
IDログむン
1ノァシャ
2ノァシャ
3ペティア
4ペティア
5むワン
6むワン
そしお今-泚意 -次のリク゚ストを実行しおみおください。
デモ から*を 遞択したす 。 some芁玠の 堎所 を テスト  Login  value = '111' 

戻りたす
IDログむン
3ペティア
4ペティア
その結果、デヌタの䞀郚はテヌブルに衚瀺され、䞀郚はむンデックスに衚瀺されたせんが、それでも怜玢を実行できたす。

これはどこで䟿利ですか

たずえば、むンデックスでは、通垞のように1぀ではなく、特定のナヌザヌが䜿甚できるパスワヌドのセット党䜓、たたはSQLを䜿甚しお開くのが望たしくないその他の機密情報を非衚瀺にできたす。 もちろん、これには他の可胜性、たずえばGRANT column-privilegeがありたす。 ただし、この堎合、ストアドプロシヌゞャを䜿甚しお保護フィヌルドにアクセスする必芁がありたす。

機密デヌタの非衚瀺続き


テヌブルのデヌタずむンデックスが保存されおいるグロヌバルを芋るず、「5.4」、「fg」などのキヌの倀は衚瀺されたせん。

^demo.testD=6
^demo.testD(1)=$lb("","")
^demo.testD(2)=$lb("","")
^demo.testD(3)=$lb("","")
^demo.testD(4)=$lb("","")
^demo.testD(5)=$lb("","")
^demo.testD(6)=$lb("","")
^demo.testI("iLogin"," 111",3)=""
^demo.testI("iLogin"," 111",4)=""
^demo.testI("iLogin"," 222",3)=""
^demo.testI("iLogin"," 222",4)=""
^demo.testI("iLogin"," 333",3)=""
^demo.testI("iLogin"," 333",4)=""
^demo.testI("iLogin"," TEST1",1)=""
^demo.testI("iLogin"," TEST1",2)=""
^demo.testI("iLogin"," TEST2",1)=""
^demo.testI("iLogin"," TEST2",2)=""
^demo.testI("iLogin"," TEST3",1)=""
^demo.testI("iLogin"," TEST3",2)=""
^demo.testI("iLogin"," VALUE",5)=""
^demo.testI("iLogin"," VALUE",6)=""

では、なぜ圌らに尋ねたのですか

この質問に答えるために、むンデックスをわずかに倉曎し、テヌブルに再入力したす。
むンデックス iLogin OnログむンKEYS、ログむンELEMENTS;

グロヌバルは別の倖芳を取りたすむンデックス付きのグロヌバルのみを提䟛したす。

^demo.testI("iLogin"," -"," 111",3)=""
^demo.testI("iLogin"," -"," 111",4)=""
^demo.testI("iLogin"," 0"," TEST1",1)=""
^demo.testI("iLogin"," 0"," TEST1",2)=""
^demo.testI("iLogin"," 1"," TEST2",1)=""
^demo.testI("iLogin"," 1"," TEST2",2)=""
^demo.testI("iLogin"," 2"," TEST3",1)=""
^demo.testI("iLogin"," 2"," TEST3",2)=""
^demo.testI("iLogin"," 5.4"," 222",3)=""
^demo.testI("iLogin"," 5.4"," 222",4)=""
^demo.testI("iLogin"," FG"," 333",3)=""
^demo.testI("iLogin"," FG"," 333",4)=""
^demo.testI("iLogin"," KEY"," VALUE",5)=""
^demo.testI("iLogin"," KEY"," VALUE",6)=""

さお、キヌ倀ず芁玠倀の䞡方を保存したした。 これは将来どのように圹立぀でしょうか

たずえば、以前に提案されたパスワヌド付きバヌゞョンでは、パスワヌド自䜓に加えお、このパスワヌドが有効になるたでの日付などを保存できたす。 そしお、私たちのリク゚ストでは、この事実を次のように䜿甚できたす。
デモ から*を 遞択したす 。 some芁玠 Login の テスト  key = '-' および value = '111' 

どこに䜕を保存するかはあなた次第です。芚えおおく必芁があるのは、キヌは䞀意ですが、倀は䞀意ではないずいうこずです。
さらに、「コレクション」むンデックスず暙準むンデックスには、远加のデヌタを保存できたす。
むンデックス iLogin OnログむンKEYS、ログむンELEMENTS[ デヌタ = ログむン 、 ログむン ELEMENTS];

このオプションを䜿甚するず、䞊蚘のリク゚ストはデヌタにアクセスできなくなりたすが、むンデックスからすべおを取埗するため、時間も節玄されたす。

日付時刻など


日付はコレクションず䜕の関係があるのでしょうか ほずんどの堎合、日、月、たたは幎のみで怜玢する必芁があるためです。 ここでの通垞のむンデックスは圹に立ちたせんが、「コレクション」むンデックスは非垞に適切です。

次の䟋を芋おみたしょう。
クラスdemo.test ExtendsPersistent
{

むンデックス iBirthDay OnBirthDayKEYS、BirthDayELEMENTS;

プロパティ BirthDay AsDate ;

ClassMethod BirthDayBuildValueArray 
䟡倀
ByRef array  AsStatus
{
倀 = ""の 堎合 {
セット 配列 0= 倀
} else {
d = $ zd  倀 、3を蚭定したす
Set array  "yy" = + $ p  d 、 "-" 、1
Set array  "mm" = + $ p  d 、 "-" 、2
Set array  "dd" = + $ p  d 、 "-" 、3
}
$$$ OKを終了OK
}

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす。 テスト  誕生日 
{ d '2000-01-01' } union allを 遞択したす
遞択 { d '2000-01-02' } すべおを結合
遞択 { d '2000-02-01' } すべおを結合
遞択 { d '2001-01-01' } ナニオンすべお
遞択 { d '2001-01-02' } すべおを結合
{ d '2001-02-01' }を 遞択したす


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

蚘入埌のテヌブルの内容は次の圢匏になりたす。
ID誕生日
12000幎1月1日
22000幎1月2日
32000幎2月1日
42001幎1月1日
52001幎1月2日
62001幎2月1日
これは非垞にシンプルで、最も重芁なこずは非垞に高速です。たずえば、2月の誕生日をすべお衚瀺するなど、日付の特定の郚分を怜玢できたす。
デモ から*を 遞択したす 。 some芁玠 BirthDay の テスト  key = 'mm' および value = 2

結果
ID誕生日
32000幎2月1日
62001幎2月1日

簡単なリスト


CachéDBMSには、単玔なリスト List 甚の特別なデヌタ型があり、区切り文字の遞択に問題がある堎合は、文字列の代わりに䜿甚できたす。
このようなフィヌルドを䜿甚するこずは、文字列を操䜜するこずず倧差ありたせん。

小さな䟋を考えおみたしょう
クラスdemo.test ExtendsPersistent
{

リスト䞊のiListの むンデックス 芁玠;

プロパティ リスト Asリスト ;

ClassMethod ListBuildValueArray
䟡倀
ByRef array  AsStatus
{
倀 = ""の 堎合 {
セット 配列 0= 倀
} else {
ptr = 0に 蚭定
while $ ListNext  value 、 ptr 、 item  {
配列の 蚭定  ptr = アむテム
}
}
$$$ OKを終了OK
}

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす。 テスト  リスト 
NULLナニオンをすべお 遞択
$ LISTBUILD  'a'  すべおを結合する
$ LISTBUILD  'b' 、 'a'  すべおを結合する
$ LISTBUILD  'b' 、 'b'  すべおを結合
$ LISTBUILD  'a' 、 'c' 、 'b' を 遞択したす。
select $ LISTBUILD  'a ,,' 、 null 、 null 


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

ODBC衚瀺モヌドのテヌブルの内容は次のようになりたす。
NoteCachéには、 デヌタを衚瀺するための論理、ODBC、およびデヌタ衚瀺オプションの 3぀のモヌドがありたす 。
ID䞀芧
1null
2a
3b、a
4b、b
5a、c、b
6「A 、、」、、
この堎合、芁玠の区切り文字は関係ないため、芁玠内の任意の文字を䜿甚できたす。

ODBCモヌドでタむプListのフィヌルドを出力する堎合、 ODBCDELIMITERパラメヌタヌはセパレヌタヌずしお䜿甚されたす。デフォルトは「、」です。

たずえば、このようなフィヌルドでは、テヌブルは次のようになりたす。
プロパティ リスト Asリスト  ODBCDELIMITER = "^" ;
ID䞀芧
1null
2a
3b ^ a
4b ^ b
5a ^ c ^ b
6、、 ^^
アむテムの怜玢は、区切られた文字列ず同じです。
デモ から*を 遞択したす 。 some芁玠 List の テスト  value = 'a ,,' 
ID䞀芧
6「A 、、」、、
INLISTのオプションはただ「コレクション」むンデックスをただ䜿甚しおいないため、䞊蚘よりも遅いこずに泚意しおください。
デモ から*を 遞択したす 。 ここで 'a ,,' inlist リストを テストしたす

コレクションリスト


䞊蚘の䟋を曞き換えたすが、単玔なリストを䜿甚する代わりに、リストコレクションを䜿甚したす。
クラスdemo.test ExtendsPersistent
{

むンデックス iListStr on ListStrELEMENTS;

Property ListStr As list OfString ;

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす 。test  liststr 
NULLナニオンをすべお 遞択
$ LISTBUILD  'a'  すべおを結合する
$ LISTBUILD  'b' 、 'a'  すべおを結合する
$ LISTBUILD  'b' 、 'b'  すべおを結合
$ LISTBUILD  'a' 、 'c' 、 'b' を 遞択したす。
select $ LISTBUILD  'a ,,' 、 null 、 null 


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

この䟋では、ほずんどすべおが同じですが、完党ではありたせん。 次のこずに特に泚意しおください。



配列コレクション


䞊蚘のように、コレクションリストではキヌを䜿甚できたせん。 配列コレクションはこの欠陥を修正したす。

次のクラスを䜜成したす。
クラスdemo.test ExtendsPersistent
{

むンデックス iArrayStr OnArrayStrKEYS、ArrayStrELEMENTS;

プロパティ str AsString ;

プロパティ ArrayStr As Of Of String String ;

ClassMethod Fill
{
sql truncate table demo。test 
sql デモに 挿入 し たす。test  str 
NULLナニオンをすべお 遞択
'aaa' union allを 遞択したす
'bbb' union allを 遞択したす
'bbb' union allを 遞択したす
'ccc' union allを 遞択したす
nullを 遞択

sql デモに 挿入 し たす 。test_ArrayStr  test 、 element_key 、 arraystr 
遞択 1、 '0' 、 'test1' すべおを結合
遞択 1、 '1' 、 'test2' すべおを結合
遞択 1、 '2' 、 'test3' すべおを結合
select 2、 '0' 、 'test1' すべおを結合
遞択 2、 '1' 、 'test2' すべおを結合
2、 '2' 、 'test3'を すべお 遞択したす。
3、 「-」 、 「111」を すべお 遞択したす。
select 3、 '5.4' 、 '222' union all
select 3、 'fg' 、 '333' union all
遞択 4、 '-' 、 '111' すべおを結合
「4」 、 「5.4」 、 「222」を すべお 遞択したす
4、 「fg」 、 「333」を すべお 遞択したす
5、 「キヌ」 、 「倀」の すべおを 遞択したす
6、 「キヌ」 、 「倀」を 遞択したす


ZWrite ^ demo.testD
ZWrite ^ demo.testI
}

}

ここで、いく぀かの明確化を行う必芁がありたす。


したがっお、 Fill メ゜ッドの埌のテヌブルの内容は次のようになりたす。

テヌブルdemo.test
IDstr
1null
2aaa
3bbb
4bbb
5ccc
6null
テヌブルdemo.test_ArrayStr
IDテストするelement_keyArraystr
1 || 010test1
1 || 111test2
1 || 212test3
2 || 020test1
2 || 121test2
2 || 222test3
3 || 5.435.4222
3 ||-3-111
3 || fg3fg333
4 || 5.445.4222
4 ||-4-111
4 || fg4fg333
5 ||キヌ5鍵䟡倀
6 ||キヌ6鍵䟡倀
1぀ではなく2぀のテヌブルがあるため、それらの間でJOINを匷制するようになりたしたが、そうではありたせん。

SQL甚のCachéDBMSによっお提䟛されるオブゞェクト拡匵を考慮するず、「-」キヌず芁玠「111」の倀を持぀文字列のdemo.testからstrフィヌルドを衚瀺するテストク゚リは、次の圢匏を取りたす。
テストIDを 遞択し 、 テスト から test- > str を 遞択したす 。 test_ArrayStr ここで element_key = '-' および arraystr = '111'
たたはそのような
ID 、 デモ から strを 遞択したす 。 test_ArrayStr- > element_key = '-' および test_ArrayStr- > arraystr = '111'の テスト

結果
IDstr
3bbb
4bbb
ご芧のずおり、すべおのデヌタは実際には1぀のグロヌバルに栌玍されおおり、Cachéはこれらのテヌブルの「関連性」を認識しおいるため、耇雑なものもJOINもありたせん。 したがっお、フィヌルドは䞡方のテヌブルから参照できたす。 demo.testテヌブルのtest_ArrayStrフィヌルドは実際には存圚したせんが、関連するテヌブルにアクセスできたす。

結論ずしお


ここで説明するむンデックスメカニズムは、 Stream.GlobalCharacterSearchableなどの䞀郚のシステムクラスで広く䜿甚されおいたす。これは、テキストストリヌムのむンデックス付けずSQLによる怜玢を提䟛したす。 この蚘事では、埋め蟌み、保存、ストリヌム、ナヌザヌ定矩、コレクションのコレクションを䜿甚するなど、さたざたな芳点から、コレクションをクラスにむンデックス付けする䟋を特に取り䞊げおいたせん。 さらに、それらの倚くでは、SQLを介しお䜜業するこずが垞に䟿利で効率的ではないこずがありたす。 たた、党文怜玢に぀いおは、ここでは説明したせん。これは、独自のむンデックスず、SQLを介した䜜業ぞのアプロヌチがある別の領域であるためです。 さらに、 SqlListTypeやSqlListDelimiterなどのプロパティの䜿甚䟋は省略されたしたが、奜奇心reader 盛な読者であれば、それらを独立しお実際に詊すこずができたす。


䟿利なリンク

Source: https://habr.com/ru/post/J182520/


All Articles