2

这个查询是前段时间在我们的系统中编写的,但是随着数据的一点点增加,这个查询的性能变得很差。我的调查显示 ( CodeCount) 查询触发另一个子查询导致执行的大量延迟。我需要优化这个 Linq 查询。任何帮助将不胜感激

  from batch in Context.VoucherCodeBatch.ToList()
                    join type in Context.VoucherCodeType on batch.VoucherTypeId equals type.VoucherTypeId
                    join voucher in Context.Voucher on batch.VoucherCodeBatchId equals voucher.VoucherCodeBatchId

                    where batchIds.Contains(batch.BatchCode)
                    group new
                    {
                        batch.BatchCode,
                        batch.CreationDate,
                        type.VoucherTypeName,
                        voucher.AllowedCount,
                        voucher.ValidFrom,
                        voucher.ValidTo,
                        batch.VoucherCodeBatchId,
                        voucher.VoucherCode
                    }
                        by new { batch.BatchCode }
                        into uniquebatch
                        select new Batch
                        {
                            BatchCode = uniquebatch.FirstOrDefault().BatchCode,
                            CreationDate = uniquebatch.FirstOrDefault().CreationDate,
                            TimesAllowed = uniquebatch.FirstOrDefault().AllowedCount,
                            ValidFrom = uniquebatch.FirstOrDefault().ValidFrom,
                            CodeCount = ((from c in Context.Voucher.ToList()
                                          where
                                              c.VoucherCodeBatchId ==
                                              uniquebatch.FirstOrDefault().VoucherCodeBatchId
                                          select c).Count()),
                            ValidTo = uniquebatch.FirstOrDefault().ValidTo,
                            CodeType = uniquebatch.FirstOrDefault().VoucherTypeName,
                            VoucherCodeBatchId = uniquebatch.FirstOrDefault().VoucherCodeBatchId
                        });
4

1 回答 1

1

第一个大问题是ToList()ObjectSet<> (EF 中的表集合)前面的右侧。

永远不要这样做,ToList()强制 EF 在处理查询之前将所有数据带入内存。(就像@Daniel Hilgarth 评论)。

其他细节是FirstOrDefault()在行前使用 get 属性:

BatchCode = uniquebatch.FirstOrDefault().BatchCode,

在这种情况下First()使用。FirstOrDefault喜欢:

BatchCode = uniquebatch.First().BatchCode,

您的查询将是这样的:

from batch in Context.VoucherCodeBatch/*.ToList()*/
join type in Context.VoucherCodeType on batch.VoucherTypeId equals type.VoucherTypeId
join voucher in Context.Voucher on batch.VoucherCodeBatchId equals voucher.VoucherCodeBatchId
where batchIds.Contains(batch.BatchCode)
group new
    {
        batch.BatchCode,
        batch.CreationDate,
        type.VoucherTypeName,
        voucher.AllowedCount,
        voucher.ValidFrom,
        voucher.ValidTo,
        batch.VoucherCodeBatchId,
        voucher.VoucherCode
    }
by new { batch.BatchCode }
into uniquebatch
select ( delegate
    {
        // If you put a operation in a query that operation will be
        // processed all times. Bacause that i removed this line from
        // the where statement.
        var vcBatchId = uniquebatch.First().VoucherCodeBatchId;

        return new Batch
            {
                BatchCode = uniquebatch.First().BatchCode,
                CreationDate = uniquebatch.First().CreationDate,
                TimesAllowed = uniquebatch.First().AllowedCount,
                ValidFrom = uniquebatch.First().ValidFrom,
                CodeCount = ((
                    from c in Context.Voucher/*.ToList()*/
                    where c.VoucherCodeBatchId == vcBatchId
                    select c).Count()),
                ValidTo = uniquebatch.First().ValidTo,
                CodeType = uniquebatch.First().VoucherTypeName,
                VoucherCodeBatchId = uniquebatch.First().VoucherCodeBatchId
            }
    });

如果这种改进不够好,您需要将此查询更改为 SQL。但我相信这种改进会表现得更好。

于 2013-06-04T13:04:56.087 回答