【问题标题】:Force LINQ to SQL to use RowNumber() instead of Top n When Using .Skip(0)强制 LINQ to SQL 在使用 .Skip(0) 时使用 RowNumber() 而不是 Top n
【发布时间】:2016-06-04 06:12:05
【问题描述】:

在使用 Skip(0) 时,有没有办法强制 LINQ to SQL 避免使用 TOP X?我有一个对每个分页结果都运行良好的查询...除了第 1 页。我已经分析了查询,并且引入了 TOP 子句只会杀死它。我很困惑为什么会这样,但确实如此。但是,使用介于 1 和 10 之间的 RowNumber 效果很好。

在使用 Skip(0) 时,有没有办法强制 LINQ to SQL 避免使用 TOP X?我有一个对每个分页结果都运行良好的查询...除了第 1 页。我已经分析了查询,并且引入了 TOP 子句只会杀死它。我很困惑为什么会这样,但确实如此。但是,使用介于 1 和 10 之间的 RowNumber 效果很好。

罪魁祸首似乎是我的 WHERE 子句中的 EXISTS 条件。生成的 SQL 如下。在 SQL 管理器中,此查询运行良好并返回 14 个结果......但是一旦我添加了 TOP 10(就像 LINQ 一样),它就会超时。但是,如果我在 where 子句中注释 EXISTS,那么问题就会消失。

SELECT 
    t0.ProtectiveOrderID, 
    t3.DocketID, 
    t3.DocketNumber AS CaseNumber, 
    t3.PartySuffix AS CaseNumberSuffix, 
    t5.FirstName AS RespondentNameFirst, 
    t5.MiddleName AS RespondentNameMiddle, 
    t5.LastName AS RespondentNameLast, 
    t5.NameSuffix AS RespondentNameSuffix,
    t4.FirstName AS ProtectedNameFirst, 
    t4.MiddleName AS ProtectedNameMiddle, 
    t4.LastName AS ProtectedNameLast, 
    t4.NameSuffix AS ProtectedNameSuffix, 
    t3.ChildNextFriendFirstName AS ChildNextFriendNameFirst, 
    t3.ChildNextFriendMiddleName AS ChildNextFriendNameMiddle, 
    t3.ChildNextFriendLastName AS ChildNextFriendNameLast, 
    t3.ChildNextFriendNameSuffix
FROM dbo.ProtectiveOrder AS t0
INNER JOIN (
SELECT MAX(t1.ProtectiveOrderID) AS value
FROM dbo.ProtectiveOrder AS t1
GROUP BY t1.DocketID
) AS t2 ON t0.ProtectiveOrderID = t2.value
LEFT OUTER JOIN dbo.Docket AS t3 ON t3.DocketID = t0.DocketID
LEFT OUTER JOIN dbo.Directory AS t4 ON t4.DirectoryID = t3.ProtectedPartyID
LEFT OUTER JOIN dbo.Directory AS t5 ON t5.DirectoryID = t3.SubjectID
WHERE 
(
    ((t4.LastName LIKE 'smith%') AND (t4.FirstName LIKE 'jane%')) 
    OR ((t5.LastName LIKE 'smith%') AND (t5.FirstName LIKE 'jane%')) 
    OR ((t3.ChildNextFriendLastName LIKE 'smith%') AND (t3.ChildNextFriendFirstName LIKE 'jane%')) 
    OR (
            -- ***************
            -- THIS GUY KILLS THE QUERY WHEN A TOP IS INTRODUCED IN THE TOP-LEVEL SELECT
            -- ***************
            EXISTS(
                    SELECT NULL AS EMPTY
                    FROM dbo.Child AS t6
                    WHERE (t6.LastName LIKE 'smith%') AND (t6.FirstName LIKE 'jane%') AND (t6.DocketID = t3.DocketID)
            )
    )
)
ORDER BY t3.DocketNumber

【问题讨论】:

  • 可能也想发布 LINQ 查询。我刚刚尝试了一些使用 Joins、Skips 和 Takes 的示例查询,每个查询都导致使用 ROW_NUMBER()。

标签: sql linq-to-sql


【解决方案1】:

重写 Skip 方法并检查输入是否为零。对于除零以外的任何值,请调用原始的跳过方法。零不要。

因此,如果您修改 dynamic.cs 中提供的 Skip,您可以这样做:

    public static IQueryable Skip(this IQueryable source, int count)
    {
        if (count == 0)
        {
            return source;
        }
        if (source == null) throw new ArgumentNullException("source");
        return source.Provider.CreateQuery(
            Expression.Call(
                typeof(Queryable), "Skip",
                new Type[] { source.ElementType },
                source.Expression, Expression.Constant(count)));
    }

【讨论】:

  • 我不明白这是如何消除 TOP 子句的。我的 .Skip(0).Take(10) 仍然使用此代码导致 TOP (10)。我想要的是 .Skip(0).Take(10) 导致 Select RowNumber()...WHERE RowNumber 介于 1 和 10 之间(因为它对于 Skip 的 0 以外的任何值都是如此)。我错过了什么吗?
  • 根据您的问题,您说 .Skip(0) 是导致 TOP(10) 发生的原因。如果你使用新的skip方法,Skip(0)基本上会导致skip不被调用。如果这不能解决问题,那么问题不是您所说的 .Skip(0) 的直接结果。删除 .Skip(0) 并留下 .Take(10) 会导致问题发生吗?
  • 是 Skip 和 Take 的结合。 .Skip(0).Take(10) 与 .Take(10) 本身一样导致 TOP (10)。只有在 Skip(x) 中有一个大于 0 的数字时,才会导致使用 RowNumber() 进行 SQL 分页。即使不跳过任何行,我也需要使用 SQL 分页运行查询。
  • 如果 .Take(10) 没有导致问题,那么你没有使用我提供的 .Skip 方法。如果您使用了该方法,那么结果看起来就像您根本没有使用 .Skip 方法一样。它很可能仍然调用 .Skip 的原始实现而不是这个。将此名称更改为 Skip 以外的名称,以便您知道正在调用正确的名称。
猜你喜欢
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-05
  • 1970-01-01
  • 2012-06-12
  • 2011-01-03
  • 1970-01-01
相关资源
最近更新 更多