たとえば、次のクエリを例とします。
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/VB9、Timothy Ng
VB チームの Web ログ - http://blogs.msdn.com/vbteam/archive/2008/03/28/linq-to-sql-and-linq-to-entities-performance-improvements-tim-ng.aspx (英語) より