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 参数是 MercerId 的 Guid,@p1 到 @p8 是数字字符串"1"thru "8",代表 paymentStatusId。

如果我跳过该行:

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似乎是字符串的集合;因此,您要求数据库转换PaymentStatusId为 nvarchar 并与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 的好/坏部分。尝试拆分查询并使用一些内存中的结果。尝试删除第一个查询(实际上没有多大意义,您返回的是相同的集合)并将第二个查询修改为这样,看看它是否有任何区别。

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 回答