LiveLinq は、インデックスを使用した最適化によってクエリーを高速化しますが、どの程度高速化されるかは、クエリーの記述方法に左右されます。通常、クエリーの記述方法による違いはそれほど大きくありません。LiveLinq は、クエリーの記述方法に関係なく、インデックスを使用した最適化の可能性を正しく認識します。たとえば、複数の項が論理演算子で接続された条件がある場合でも、インデックスを使用して効率よくクエリーを実行します。
インデックスが LiveLinq によって効率よく使用されるようにするには、次のガイドラインに従うことをお勧めします。
インデックスのメリットがある基本述語
LiveLinq は、下記の (1) 〜 (6) のいずれかの形式(パターン)を持つ基本述語(ブール演算を含まない条件)で、プロパティ P に基づくインデックスを使用できます。最も単純で、おそらく最もよく使用される基本述語は、1つのプロパティを含む等式から成る次のような where 条件です。
コードのコピー
|
|
---|---|
from x in X where x.P == 1 select x |
この場合は、x.P に基づくインデックスが使用されます(インデックスがある場合)。「インデックスの作成方法」で説明されているように、インデックスを確実に使用するには、次のように明示的にインデックスを作成するか、
コードのコピー
|
|
---|---|
X.Indexes.Add(x => x.P); |
次のように Indexed() メソッドヒントを使用します。
コードのコピー
|
|
---|---|
from x in X where x.P.Indexed() == 1 select x |
実際には、LiveLinq は、より一般的なインデックスをサポートしています。これが x のプロパティである必要はなく、x に依存する(かつ x だけに依存する)式であれば何でもかまいません。これは便利な機能です。たとえば、型付きでない ADO.NET DataTable をクエリーする場合、これは型付きでないため、名前に基づくインデックスやクエリーを行うためのプロパティがありません。そこで、次のようなクエリーを使用する必要があります。
コードのコピー
|
|
---|---|
from c in customersTable.AsIndexed() where c.Field<string>("CustomerID") == "ALFKI" select x |
次に、以下の式でインデックスを使用できます。
コードのコピー
|
|
---|---|
X.Indexes.Add(c => c.Field<string>("CustomerID")); |
以下に、LiveLinq によってインデックスを使用した最適化が可能と認識されるパターンを示します。
x.P == Const(Const は、この特定のクエリー演算子で不変の値。これは、外部のパラメータや変数に依存する式でもかまいませんが、この where 条件でテストされるすべての要素に対して同じ値を持つ必要があります)。
例:
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.OrderID.Indexed() == 10011 |
x.P op Const(op は比較演算子 >、>=、<、<= のいずれか)。
例:
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.OrderID.Indexed() > 10011 |
例:次のクエリーでは、(1) の例とまったく同じインデックスが使用されます。
Example Title |
コードのコピー
|
---|---|
from o in Orders.AsIndexed() where 10011 == o.OrderID.Indexed() |
x.P.StartsWith(Const)(x.P が文字列型の場合)。
例:
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.CustomerID.StartsWith("A") |
ConstColl.Contains(x.P)(ConstColl が IEnumerable<T> を実装する場合。T は x.P 型)。
例:
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where (new int[]{"ALFKI", "ANATR", "ANTON"}).Contains(o.CustomerID) |
x.P.Year op Const(x.P は DateTime 型。op は比較演算子 ==、>、>=、<、<= のいずれか)。
例:
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.Date.Indexed().Year == 2008 |
他の基本述語では、インデックスが使用されません。以下に、インデックスが使用されない例を示します。
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.Freight > 10 (Freight プロパティにインデックスが定義されていない場合) |
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.OrderID.Indexed() < o.Freight (比較対象は変数値ではなく定数である必要があります) |
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.OrderID.Indexed() != 10011 (使用できる比較は限られます。!(等しくない)は含まれません) |
連言(&&)および選言(||)は、これらの任意の組み合わせやかっこも含め、LiveLinq オプティマイザによって処理されます。否定(!)などの他のブール演算子は、オプティマイザによって処理されません。これらの演算子はインデックスの使用を妨げます。
連言は、インデックスの使用を妨げません。次に例を示します。
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.Freight > 10 && o.Lines.Count > 5 |
このクエリーでは、Freight プロパティに基づくインデックスが使用されます(インデックスがある場合)。ただし、2番目の条件には使用できません。LiveLinq は、最初の条件でインデックスを使用して見つかった各項目に対して、2番目の条件をチェックします。
同じプロパティを使用した条件の連言
さらに、同じプロパティを使用した条件の連言は、最適な実行プランが得られるように最適化されます。たとえば、Freight プロパティにインデックスが作成されているとします。
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.Freight > 10 && o.Freight < 20 |
このクエリーは、Freight > 10 であるすべての注文を調べて、そのそれぞれで Freight が 20 より小さいかどうかをチェックするのではなく、インデックスを使用して Freight が 10 〜 20 である注文に直接移動し、その他の注文はチェックしません。
次に、別のプロパティを使用した連言の例を示します。
コードのコピー
|
|
---|---|
from o in Orders.AsIndexed() where o.CustomerID == "ALFKI" && o.Freight < 20 |
このクエリーではサブインデックスを使用できます(「Subindex(T, TKey) クラス」を参照)。CustomerID に基づくインデックスに Freight に基づくサブインデックスがある場合、LiveLinq は、CustomerID が "ALFKI" と等しい注文(大量である可能性があります)のすべてはチェックしません。LiveLinq は、値 "ALFKI" に対応するサブインデックスに直接移動し(サブインデックスがある値のみ。検索せずに直接アクセスできます)、Freight が 20 未満であるサブインデックス内の項目を列挙します。どちらの操作も(サブインデックスを見つけて、それに含まれる項目を列挙する操作)、検索のない直接的なアクセスです。結果に影響しない項目をチェックする時間がないため、クエリーは最速で実行されます。
コードのコピー
|
|
---|---|
(a) x.P をインデックス付きプロパティとすると、
x.P == Const1 || x.P == Const2
このクエリーは、条件を次のように書き換えることによって処理されます。
(new ...[]{Const1, Const2}).Contains(x.P)
|
コードのコピー
|
|
---|---|
(b) 2つのプロパティ x.P および x.Q にインデックスが作成されている場合、
x.P op Const1 || x.Q op Const2 (op is ==, <, >, <=, etc)
このクエリーは、対応する基本条件を持つ2つのクエリーの和結合に書き換えることによって処理されます。
|
次のクエリーの結合に含まれる2つのキーセレクタのいずれか(x.K または y.K)にインデックスが作成されている場合、
コードのコピー
|
|
---|---|
from x in X join y in Y on x.K equals y.K |
LiveLinq は、そのインデックスを使用して結合を実行します。
x.K と y.K の両方にインデックスがあれば理想的です。その場合、LiveLinq は、マージ結合と呼ばれるアルゴリズムを使用して、結合を極めて高速に実行します。このアルゴリズムは高速で、基本的に結合の結果を走査するためにかかる時間と同程度であり、余計な時間はかかりません。
x.K と y.K の両方にインデックスがない場合でも、LiveLinq は、結合に最適なアルゴリズムを見つけようとします。マージ結合が使用されることも(結合の両方の側がマージキーで並べ替えられている場合)、標準の LINQ to Objects で使用されるハッシュ結合アルゴリズムが使用されることもあります。
一般に、クエリー内の結合操作を最適化する目的でのみインデックスを定義しても、速度が劇的に向上することはほとんどありません。これは、ハッシュ結合アルゴリズム(インデックスを必要としない、標準の LINQ で使用されるアルゴリズム)が十分に速いためです。結合キーにインデックスを定義することに意味があることもありますが、クエリー速度を劇的に向上させる手軽な方法としてではなく、あくまでもクエリーを微調整する方法として検討してください。速度を劇的に向上させるには、最初に Where 条件の最適化を検討します。クエリーにもよりますが、この最適化によって速度が数百倍から数千倍に向上する可能性があります。