データストアのクエリ
昨日の続きです。
複数のプロパティに関するフィルタ
ここで注目したい内容があります。それはインデックスのプロパティの順番です。先ほどのクエリはこんな感じでした。
SELECT * FROM Player WHERE charclass = 'ヒーロー' AND level < 10
ここでプロパティの出現順序はもちろん、charclass (クラス) → level (レベル) です。でインデックスはこんな感じです。
キー | クラス | レベル |
---|
素直に出現順序のまま並んでいます。では次のクエリだとどうなるでしょうか?
SELECT * FROM Player WHERE level < 10 AND charclass = 'ヒーロー'
実はインデックスのプロパティの出現順序は変わりません。つまり等号フィルタに利用されているプロパティの方がインデックスでは先に出現する、ということです。本書ではこのルールのことを不等号フィルタの第1ルールと書かれています。ちなみに出現順がGQLの出現順と一致していると次のようなインデックスになります。
キー | レベル | クラス |
---|---|---|
ゴレンジャーのキー | 2 | ヒーロー |
ウルトラマンのキー | 7 | ヒーロー |
バルタン星人のキー | 21 | 怪獣 |
仮面ライダーのキー | 22 | ヒーロー |
ショッカーのキー | 24 | 悪者 |
単純な行のスキャンでは目的の結果が得られないのが分かります。うまく出来てますね。
では次のようなパターンの場合はどうでしょうか?
SELECT * FROM Player WHERE level < 10 ORDER BY score
levelプロパティの値が10未満のエンティティをscoreプロパティの値を昇順にソートするクエリです。この時のインデックスがどうなっているのか?たとえばこんな感じはどうでしょうか。
キー | レベル | 得点 |
---|---|---|
ゴレンジャー | 2 | 2003 |
ウルトラマン | 7 | 1366 |
バルタン星人 | 21 | 2003 |
仮面ライダー | 22 | 1096 |
ショッカー | 24 | 33311 |
あれれ?目的の結果が得られませんね。scoreプロパティの値が昇順にソートされていません。かと言ってレベルと得点の出現順序を逆転させても当然うまく行きません。
キー | 得点 | レベル |
---|---|---|
仮面ライダー | 1096 | 22 |
ウルトラマン | 1366 | 7 |
ゴレンジャー | 2003 | 2 |
バルタン星人 | 2003 | 21 |
ショッカー | 33311 | 24 |
通常このようにフィルタで利用しているプロパティ以外のプロパティでソートする場合、明示的にフィルタで利用しているプロパティのソート順序を指定する必要があります (そうしないと例外が発生します) 。こんな感じ。
SELECT * FROM Player WHERE level < 10 ORDER BY level, score
この場合、次のようなインデックスが作られます。
キー | レベル | 得点 |
---|---|---|
ゴレンジャー | 2 | 2003 |
ウルトラマン | 7 | 1366 |
バルタン星人 | 21 | 2003 |
仮面ライダー | 22 | 1096 |
ショッカー | 24 | 33311 |
ここで得られる結果はこんな感じ。
キー | レベル | 得点 |
---|---|---|
ゴレンジャー | 2 | 2003 |
ウルトラマン | 7 | 1366 |
う〜ん、やっぱり得点ではソート出来ないのですね。SQLであれば、きっと
キー | レベル | 得点 |
---|---|---|
ウルトラマン | 7 | 1366 |
ゴレンジャー | 2 | 2003 |
という結果が得られるはずです。これはApp Engineの (データストアの) 制約なんでしょうかね。むしろこのような制約があるから、不等号フィルタで利用しているプロパティでソート指定させているんでしょうね。そうしないとこの結果は不正ですからね。
このように不等号フィルタで利用しているプロパティではじめにソートする必要がある、というルールのことを本書では不等号フィルタの第2ルールと呼んでいます。
そしてデータストアの最大の制約と思える項目があります。たとえば以下のクエリを考えてみます。
SELECT * FROM Player WHERE level < 10 AND score < 500
SQLではいかにもありそうなクエリですよね。でもこのクエリはApp Engineでは不正なクエリとなります。たとえば次のようなエンティティの列があったとします。
レベル | 得点 |
---|---|
8 | 498 |
10 | 498 |
9 | 499 |
8 | 500 |
このようなエンティティ列に関しては、どのようにインデックスを作成しても目的のエンティティ列は取得出来ません。
レベル → 得点の順でソートした場合のインデックス
レベル | 得点 |
---|---|
8 | 498 |
8 | 500 |
9 | 499 |
10 | 498 |
得点 → レベルの順でソートした場合のインデックス
得点 | レベル |
---|---|
498 | 8 |
498 | 10 |
499 | 9 |
500 | 8 |
どちらも目的のエンティティ列を取得することは出来ません。連続した行として表現出来ないのです。
これが本書で不等号フィルタの第3のルールと呼ばれている内容です。つまり一つのクエリで複数のプロパティに対して不等号フィルタは使えないのです。興味深い制約ですよね。
なお、同じプロパティに対して複数の不等号フィルタを使うことは可能です (範囲指定とか) 。