Partager via


LINQ to SQL (および LINQ to Entities) のパフォーマンスの改善 (Tim Ng)

ここ数か月間、VB チームと Data Programmability チームは LINQ to SQL (LINQ to Entities のマニフェスト内にもあります) のパフォーマンス上の問題の解決に取り組んできました。問題というのは、VB LINQ クエリに Null 許容型の列を対象とするフィルタが含まれる場合、LINQ to SQL で生成される T-SQL クエリが最適化されないことです。

たとえば、次のクエリを例とします。

 Dim q = From o In db.Orders Where o.EmployeeID = 123 Select o.CustomerID 

このシナリオでは、Orders.EmployeeID フィールドは Null 許容型のフィールド (Integer?) です。VB では、論理演算子 (<、<=、= など) は 3 値論理演算子と見なされるため、等式の比較結果は "Boolean?" 型の値となります。しかし、LINQ 演算子は "Boolean" 型の値が返されることを予想し、"Boolean?" 型ではないため、VB では合体演算子を使用して "Boolean?" を "Boolean" に変換する必要があります (詳細については、式ツリーと合体演算子 (英語) に関するブログの記事を参照してください)。

LINQ to SQL は合体演算子を最適化できますが、VS 2008 RTM では、述語論理から 3 値論理 (およびその逆) に変換されるため、列の該当するインデックスが飛んでしまうことがあります。

VS 2008 RTM で生成される SQL の例を次に挙げます。

 

SELECT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]
WHERE (COALESCE(
(CASE
WHEN [t0].[EmployeeID] = @p0 THEN 1
WHEN NOT ([t0].[EmployeeID] = @p0) THEN 0
ELSE NULL
END),@p1)) = 1
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [123]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]

朗報

この問題に関し、LINQ to SQL チームは、このパターンに該当する LINQ to SQL のコード生成の修正方法を見つけ出し、予想されるとおりに、次の SQL コードが生成されるようになりました。

SELECT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[EmployeeID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [123]

つまり、LINQ to SQL (および同様の修正を加えた LINQ to Entities) は VB から SQL に対し、適切な 3 値論理を渡すようになったのです。

この具体例では、VB と SQL はどちらも 3 値のブール論理を使用しますが、中間層である LINQ 演算子が 2 値のブール論理を使用し、層の間の変換が行われなかったため、最適化されないコードが VS2008 RTM で生成される結果となっていました。この修正については、後日年内にリリースされる更新プログラムをお待ちください。

VB チーム

投稿 : 2008 年 3 月 28 日 8:58 AM

分類 : LINQ/VB9Timothy Ng

VB チームの Web ログ - https://blogs.msdn.com/vbteam/archive/2008/03/28/linq-to-sql-and-linq-to-entities-performance-improvements-tim-ng.aspx (英語) より