2

私は特定のマーチャントへの注文を示すレポートを持っており、支払いステータスのフィルターを追加する必要があるまでは正常に機能していました。

これは、フィルターごとにフィルターするクエリを作成する方法です。

var queryOrder = context.Orders.Select(m=>m);

if (viewModel.InitialDate.HasValue)
    queryOrder = queryOrder.Where(m => m.CreatedDate.Date >= viewModel.InitialDate.Value);

(...) /* continues building the query, filter by filter */


if (viewModel.SelectedPaymentStatus != null)
    queryOrder = queryOrder.Where(m => viewModel.SelectedPaymentStatus.Contains(m.Payments.Select(p => p.PaymentStatusId).Single().ToString()));

queryOrder = queryOrder.Where(m => m.MerchantId == merchantId);

を実行するqueryOrderと、 だけでもqueryOrder.Count()実行に 1 分以上かかります。SQL Server のプロファイリング ツールを使用して、生成されたクエリを次のように抽出しました。

SELECT [t0].[Id], [t0].[CustomerId], [t0].[MerchantId], [t0].[OrderNumber], [t0].[Amount], [t0].[SoftDescriptor], [t0].[ShippingMethod], [t0].[ShippingPrice], [t0].[IpAddress], [t0].[SellerComment], [t0].[CreatedDate]
FROM [dbo].[Order] AS [t0]
WHERE ([t0].[MerchantId] = @p0) 
AND ((CONVERT(NVarChar,(
       SELECT [t1].[PaymentStatusId]
       FROM [dbo].[Payment] AS [t1]
       WHERE [t1].[OrderId] = [t0].[Id]
    ))) IN (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8))

@p0 パラメータは MerchantId の Guid であり、@p1 から @p8 までの数値文字列は、 "1"paymentStatusId"8"を表します。

行をスキップした場合:

if (viewModel.SelectedPaymentStatus != null)
    queryOrder = queryOrder.Where(m => viewModel.SelectedPaymentStatus.Contains(m.Payments.Select(p => p.PaymentStatusId).Single().ToString()));

クエリは 1 秒未満で実行されます。しかし、私がそれを使用すると、パフォーマンスは床にぶつかります。これを解決する方法に関するヒントはありますか?

4

2 に答える 2

0

問題スニペットに注釈を付けました:

if (viewModel.SelectedPaymentStatus != null) {

    // Give me only orders from queryOrder where...
    queryOrder = queryOrder.Where(

        // ...my viewModel's SelectedPaymentStatus collection...
        m => viewModel.SelectedPaymentStatus.Contains(

                 // ...contains the order's payment's PaymentStatusId...
                 m.Payments.Select(p => p.PaymentStatusId).Single()

                                          // ... represented as a string?!
                                         .ToString()
                                          // Why are database IDs strings?
             )
        );
}

viewModel.SelectedPaymentStatus文字列のコレクションのようです。したがって、データベースにPaymentStatusIdnvarcharに変換し、の要素と文字列比較を行うように要求していますSelectedPaymentStatus。うん。

は小さいので、一時的なものを作成してクエリで使用するviewModel.SelectedPaymentStatus方がよい場合があります。List<int>

if (viewModel.SelectedPaymentStatus != null) {

    // Let's do the conversion once, in C#
    List<int> statusIds = viewModel.SelectedPaymentStatus.Select( i => Convert.ToInt32(i) ).ToList();

    // Now select the matching orders
    queryOrder = queryOrder.Where(
                     m => statusIds.Contains(
                              m.Payments.Select(p => p.PaymentStatusId).Single())
                          )
                 );
}
于 2013-03-21T20:33:09.210 に答える
0

すべてのクエリが延期され、これは linq の良い部分と悪い部分の両方です。クエリを分割して、メモリ内の結果を使用してみてください。最初のクエリを削除してみて (あまり意味がありません。同じコレクションを返しています)、2 番目のクエリを次のように修正して、違いがあるかどうかを確認してください。

var clause = context.Orders.Payments.Select(p => p.PaymentStatusId).Single().ToString();
if (viewModel.SelectedPaymentStatus != null)
    var queryOrder = context.Orders.queryOrder.Where(m => viewModel.SelectedPaymentStatus.Contains(clause));
于 2013-03-21T15:01:19.760 に答える