2015-11-05 9 views
9

こんにちは私は自分のプロジェクトにMVC 5Entity Framework 6を使用しています。 私は、次の図のようなモデルがあります:相関エンティティで検索

diagram

をそして私はTagオブジェクトのセットから開始することにより、エンティティの製品を照会する必要があります。 Tagオブジェクトは、Table-Per-Entity戦略継承を使用して実際にマップされる抽象クラスです。

これは実際Tag実装の具体的なインスタンスが存在するであろう私の関数法タグリストパラメータの

public IEnumerable<Product> SerachByTag(IEnumerable<Tag> tagList); 

の署名です。

このクエリはどのように作成できますか?

は、例えばIは、データ構造

[ 
    { tagType: 1, stringProperty: "abc" }, 
    { tagType: 2, intProperty: 9 } 
] 

など以下の入力で受信することができます。これは、製品をフィルタリングするより良い方法でしょうか?たとえば、私は確かに最初にすべての単一の基準について製品のリストを適用し、次のサンプルのように、これらの結果を交差することができます:

var p1 = ctx.Tags 
      .OfType<FirstTagType>() 
      .Where(x => x.StringProperty.Equals("abc")) 
      .Select(x => x.Products); 
var p2 = ctx.Tags 
      .OfType<SecondTagType>() 
      .Where(x => x.IntProperty == 9) 
      .Select(x => x.Products); 
var results = p1.Intersect(p2); 

をしかし、この場合、私の質問は公演についてです。このクエリは多くのフィルタでどのように動作しますか?

+0

製品のクエリを実行しているだけで(具体的なタグの種類は気にしない)、(抽象的な)タグdbsetを照会するだけです。 –

+0

@AlexKrupka:あなたの答えをありがとう。残念ながら私は具体的なタイプを考慮する必要があります – Lorenzo

答えて

5

あなたのクエリのために生成されたSQLをチェックアウトする場合は、似たような見つけることができます:ここで

SELECT 
[Intersect1].[ProductId] AS [C1], 
[Intersect1].[ProductName] AS [C2] 
FROM (SELECT 
    [Extent3].[ProductId] AS [ProductId], 
    [Extent3].[ProductName] AS [ProductName] 
    FROM [dbo].[FirstTag] AS [Extent1] 
    INNER JOIN [dbo].[Tag] AS [Extent2] ON [Extent1].[TagId] = [Extent2].[TagId] 
    LEFT OUTER JOIN [dbo].[Product] AS [Extent3] ON [Extent2].[Product_ProductId] = [Extent3].[ProductId] 
    WHERE N'aaaa-9' = [Extent1].[StringProperty] 
INTERSECT 
    SELECT 
    [Extent6].[ProductId] AS [ProductId], 
    [Extent6].[ProductName] AS [ProductName] 
    FROM [dbo].[SecondTag] AS [Extent4] 
    INNER JOIN [dbo].[Tag] AS [Extent5] ON [Extent4].[TagId] = [Extent5].[TagId] 
    LEFT OUTER JOIN [dbo].[Product] AS [Extent6] ON [Extent5].[Product_ProductId] = [Extent6].[ProductId] 
    WHERE -9 = [Extent4].[IntProperty]) AS [Intersect1] 

は、あなたが内側のSELECTクエリがあなたの期待を正確に何をやっていることがわかりますが。結合は外部キーに基づいており、列の索引を使用して高速化する必要があります。したがって、多くのフィルタを使用している場合は、適切にインデックスを作成したカラムですべてのフィルタを処理するだけです。

LINQ Intersectは、SQL INTERSECTに翻訳されています。これは、「製品」テーブルのすべての列で機能します。あなたの側で実際の実行計画をチェックしたいかもしれませんが、それは多くのことに依存するかもしれません。

私の見ているところでは、SQL Serverは最初のクエリを実行し、結果では「Distinct Sort」を呼び出し、次に実際の交差を実行するために「Left Semi Join」をProductIdProductName(Productテーブルのすべての列)。私の推測では、すべての列にインデックスを持たないため、これは最善ではないかもしれません。これを最適化する

一つの方法は、プライマリキー(それは高速である必要があります)上で交差を行い、その後、IDに基づいて、すべての製品データをフェッチすることです。

var p1 = ctx.Tags 
    .OfType<FirstTag>() 
    .Where(x => x.StringProperty.Equals("aaaa-9")) 
    .Select(x => x.Product.ProductId); 
var p2 = ctx.Tags 
    .OfType<SecondTag>() 
    .Where(x => x.IntProperty == -9) 
    .Select(x => x.Product.ProductId); 

var query = ctx.Products.Where(p => p1.Intersect(p2).Contains(p.ProductId)); 

生成され、基礎となるSQLクエリの使用EXISTSであり、その実行計画は内部結合(主キー上)を使用します。

しかし、パフォーマンスの問題があるかどうかを最初に確認することなく、この最適化プロセスを実際には開始しません。

関連する問題