インデックスへの参照が無効になるwhereステートメントの書き方を把握して、なるたけ回避する

インデックスはつけてされいれば、いつでもSASがそれを使って高速に処理してくれる
というものではありません。

インデックスの参照が無効化されるケースがあるので
回避できる部分はプログラマが気をつけなければいけません。


とはいえ、SASの場合は、実のところ他のRDBMSに比べて、結構強力に参照してくれます。
たとえば変数Xに単一インデックスXがついていた場合

where X ^=1;

where X not in (1,2);
where X is null;
where substr(X,1,1)='A';

などは他のシステムでは定番で強制的にインデックス非参照の場合が多いのですが
SASはそうではありません。

で、詳しくはSAS9.3言語リファレンス 解説編をSASのホームページの日本語版SASオンラインヘルプから落としてきて、26章 SASデータファイルのSASインデックスについてのWHERE式処理に対するインデックスの使用の項あたりを読んでください。

以上。

だと、あまりにそっけないので大原則だけ実践で説明します。
まず、インデックスが使用されたかどうかを判別できるoptions msglevel=i;をしてから
以下のデータセットを作成します。

options msglevel=i;

data Q1(index=(X YZ=(Y Z)));
do X=1 to 10;
 Y=X**2;
 Z=X**3;
 output;
end;
run; 

変数Xでもって単一インデックスXをつくり
変数YとZのペアで複合インデックスYZをつくっています。

では早速

data OK;
 set Q1;
 where X<5;
run;










この場合インデックスXが参照されます。


では、次に

data NG;
 set Q1;
 where X-5<0;
run;

を実行すると









インデックスXが参照されることは決してありません。
式変形しただけで、抽出の意味は同じなのに
インデックスが利用される場合とされない場合があるというのは
こういうことです。

で、原則としては
whereステートメントの左辺は裸にするということです。
余計な四則演算や関数をつけているとインデックスは利用されないので
全部どうにかして右辺につっこみましょう。
※ただし、TRIM関数とSUBSTR関数は例外的に使用できます。

次は少し応用編なのですが、

data OK;
 set Q1;
 where Y=1 and  Z=1;
run;











を実行すると、YとZにインデックスYZをはっているので、参照されます。

しかし、

data OK;
 set Q1;
 where Y=1;
run;

のように変数Yだけで実行するとどうなるでしょうか?










なんとYZが参照されるのです。
このように複合インデックスにおいても、インデックスの一部要素である変数を
抽出式に利用すると、部分的に利用してくれるわけです。

じゃあ同じ理屈で
data NG;
 set Q1;
 where Z=1;
run;

のようにZだけで実行すると、









次は、なんとインデックスが参照されません。
これは、実はインデックスを作成する際に(index=(X YZ=(Y Z)))と
Y Zの順番に宣言しているからなのです。
つまり、複合インデックスは、部分的に内包される変数で利用できるが
宣言順通りにならない場合は、無効化されるということです。

なので、例えば症例番号とビジットで一意になるデータがあった際に
複合インデックスを(症例番号 ビジット)で作るのか(ビジット 症例番号)でつくるのかは
その後、個別に症例を抽出するような処理の発生が考えられるか、あるいはビジットごとに
全症例を抽出するような処理が発生するか、どちらであるかを考慮して作成するといいですねと
いった話でした。

なお複合最適化についても詳しくはリファレンスを参照してください。




0 件のコメント:

コメントを投稿