首页 > 解决方案 > Linq-to-SQL 谓词 VS UNION

问题描述

我有桌子OrderOrderItem。现在,我需要获取一系列订单的所有订单项目(例如,整个月的订单)。订单订单项目本身有很多列。因此,使用速度非常慢。Include("OrderItem")

订单记录数量约为每月 20K 记录,订单项目约为 50K-60K 记录。

由于目前是一个日期范围(例如,每天、每周、每月、每年等),我正在做 2 次选择。

var orders = (from rec in Orders.AsNoTracking()
              where (rec.OrderDate >= startDate) && (rec.OrderDate <= endDate)
              orderby rec.OrderDate descending
              select rec).ToList();

var orderItems = (from rec in OrderItems.AsNoTracking()
                  join recOrder in Orders.AsNoTracking() on new { rec.LocationId, rec.StoreId, rec.OrderId } equals new { recOrder.LocationId, recOrder.StoreId, recOrder.OrderId }
                  orderby recOrder.OrderDate descending
                  where (recOrder.OrderDate >= startDate) && (recOrder.OrderDate <= endDate)
                  select rec).ToList();

这一切都很好。但是,当我进行分页时(根据用户偏好,每页可以显示 25 - 1000 条记录),我想摆脱 2 次选择并使用联合或谓词(在 LinqKit 中使用 PredicateBuilder),如下所示:

var orders = (from rec in Orders.AsNoTracking()
              where (rec.OrderDate >= startDate) && (rec.OrderDate <= endDate)
              orderby rec.OrderDate descending
              select rec).Skip(page * recPerPage).Take(recPerPage).ToList();

现在,要获得订单项目,我建议使用 3 个选项。请让我知道哪一个更适合小记录(每页 25 - 1000 条记录)。

选项#1:使用另一个选择与Skip and Take订购商品

选项#2:使用联合。

IQueryable<OrderItem> queries = null;
foreach (Tuple<int, int, int> key in orderIds)
{
    int locationId = key.Item1, storeId = key.Item2, orderId = key.Item3;
    var recs = (from rec in OrderItems.AsNoTracking()
                where (rec.LocationId == locationId) && (rec.StoreId == storeId) && (rec.OrderId == orderId)
                select rec);
    queries = (queries == null) ? recs : queries.Union(recs);
}
var orderItems = queries.ToList();

选项 #3:使用 PredicateBuilder。

var predicate = PredicateBuilder.New<OrderItem>();
foreach (Tuple<int, int, int> key in orderIds)
{
    int locationId = key.Item1, storeId = key.Item2, orderId = key.Item3;
    predicate = predicate.Or(rec => (rec.LocationId == locationId) && (rec.StoreId == storeId) && (rec.OrderId == orderId));
}
var orderItems = OrderItems.AsNoTracking().AsExpandable().Where(predicate).ToList();

我更喜欢使用UnionPredicateBuilder来获取订单项,该函数不必知道是否使用日期范围按产品搜索按客户搜索任何其他未来搜索选项选择了订单。所有OrderItem需要知道的是订单 ID 列表。

所以,我的问题是,就速度和性能而言,哪个选项是最好的选择?

笔记:

如果我尝试获取 1000 条记录,有时 Union 和 PredicateBuilder 会抛出 StackOverflowException。因此,我将其限制为 500 条记录。如果用户偏好是 1000 条记录,那么,我会打 2 次电话。

我还尝试使用 LINQPad 查看谓词生成器生成的 SQL,但它无法识别AsExpandable()(是的,我已包含 LinqKit DLL)。所以,这里没有运气。

请帮忙。

谢谢。

标签: c#performanceentity-frameworkentity-framework-6linq-to-entities

解决方案


推荐阅读