2

そのため、SQLServerデータベースにアクセスするためのさまざまな方法のプロファイリングを行っていました。バニラTSQL、CompiledQuery、およびコンパイルされていないLinqステートメントを実行しました。

予想通り、パフォーマンスは同じ順序で進んでいましたが、後者の2つをプロファイリングすると、何か不思議なことに気づきました。

CompiledQueryによって生成されたSQLは、単純な古いステートメントによって生成されたものよりもはるかに優れていました。

ローカルSQLExpressデータベース。テーブルは「foreignTable」と呼ばれ、ColumnAはint、主キー(インデックス付き)です。ColumnBはランダムなintです。

Func<testingDatabaseEntities1, int, int> GetByPK = CompiledQuery.Compile((testingDatabaseEntities1 ft, int key) 
  => (ft.foreignTable.Where(x => x.ColumnA == key).FirstOrDefault().ColumnB));

生成します

SELECT 
[Project1].[ColumnB] AS [ColumnB]
FROM   ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN  (SELECT TOP (1) 
    [Extent1].[ColumnB] AS [ColumnB]
    FROM [dbo].[foreignTable] AS [Extent1]
    WHERE [Extent1].[ColumnA] = @p__linq__1 ) AS [Project1] ON 1 = 1

これは、生成されたコードの場合、実際にはそれほどひどいものではありません。

しかし、私が単純なLinqステートメントを実行すると:

entity.foreignTable.Where(x => x.ColumnA == searchForMe).FirstOrDefault().ColumnB

それは生成します:

SELECT 
[Limit1].[C1] AS [C1], 
[Limit1].[ColumnA] AS [ColumnA], 
[Limit1].[ColumnB] AS [ColumnB], 
[Limit1].[FKColumn] AS [FKColumn]
FROM ( SELECT TOP (1) 
    [Extent1].[ColumnA] AS [ColumnA], 
    [Extent1].[ColumnB] AS [ColumnB], 
    [Extent2].[FKColumn] AS [FKColumn], 
    1 AS [C1]
    FROM  [dbo].[foreignTable] AS [Extent1]
    LEFT OUTER JOIN (SELECT 
      [Table_2].[FKColumn] AS [FKColumn], 
      [Table_2].[SomeText] AS [SomeText]
      FROM [dbo].[Table_2] AS [Table_2]) AS [Extent2] ON [Extent1].[ColumnA] = [Extent2].[FKColumn]
    WHERE [Extent1].[ColumnA] = @p__linq__7
)  AS [Limit1]

これはただくだらないです。

ですから、質問は次のように思います。通常のLinqをエンティティにCompiledQueryと同じ量のSQLサッキーを与えることは可能ですか?

4

2 に答える 2

5

比較しているクエリは同じではありません。最初のコンパイル済みクエリは、1 つのプロパティのみを返します。異なるものを返すことはできません。2 番目は、逆参照してからプロパティにアクセスするエンティティ インスタンスを返します。クエリが実行されるとき、1 つのプロパティのみを参照するつもりであることを知る方法はありません。

コンパイルされていないクエリから同じ SQL を取得できる (テストされていない) 1 つの方法は、匿名型に射影することです。

var b = (from e in entity.foreignTable.
         where ColumnA == searchForMe
         select new 
         {
            ColumnB = e.ColumnB
         }).FirstOrDefault().ColumnB;
于 2009-03-31T17:43:24.277 に答える
3

コンパイルされたクエリは、そのクエリを数回使用することが予想されるため、余分な作業を行っています。それがあなたの求めているものである場合は、コンパイルされたクエリに固執してください。

この特定のシナリオでは、次のことを行います。

entity.foreignTable
    .Where(x => x.ColumnA == searchForMe)
    .Select(x=>x.ColumnB)
    .FirstOrDefault();

これはまったく同じではありませんが、(ColumnB のみを取得するために) 期待どおりのクエリになることは間違いありません。FirstOrDefault を実行するとインスタンスが得られるため、linq2sql クエリの後に .ColumnB が発生しています。この新しいクエリは、ColumnB のデフォルト (null または ColumnB の定義に応じた特定の値) を提供する一方で、null 参照のためにバージョンが失敗するため、動作にも違いが生じます。

于 2009-03-31T17:07:53.333 に答える