【问题标题】:How do I write LINQ's .Skip(1000).Take(100) in pure SQL?如何在纯 SQL 中编写 LINQ 的 .Skip(1000).Take(100)?
【发布时间】:2010-12-17 05:14:58
【问题描述】:

LINQ 中 .Skip() 方法的 SQL 等效项是什么?

例如:我想从特定的数据库表中选择第 1000-1100 行。

仅使用 SQL 是否可能?还是我需要选择整个表,然后在内存中查找行?如果可能的话,我最好避免这种情况,因为表格可能非常大。

【问题讨论】:

    标签: .net sql sql-server


    【解决方案1】:

    SQL Server 2012 及更高版本已添加此语法:

    SELECT *
    FROM Sales.SalesOrderHeader 
    ORDER BY OrderDate
    OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY
    

    【讨论】:

    • 请注意,您需要使用 ORDER BY ___ 才能使用 OFFSET 命令....并不是说您应该尝试在没有订单的情况下进行分页。
    • 另请注意,“新”语法奇怪地具有与@skip 线性相关的性能损失! row_number 方法没有这个(仅在索引顺序上测试)。对于 lo @Skip 少于 20,新语法比 row_number 方法更快。
    【解决方案2】:

    在 SQL Server 2005 及更高版本中,您可以使用ROW_NUMBER 函数。例如。

    USE AdventureWorks;
    GO
    WITH OrderedOrders AS
    (
        SELECT SalesOrderID, OrderDate,
        ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
        FROM Sales.SalesOrderHeader 
    ) 
    SELECT * 
    FROM OrderedOrders 
    WHERE RowNumber BETWEEN 51 AND 60; --BETWEEN is inclusive
    

    【讨论】:

    • 有关详细信息,请参阅我的答案中的链接。 stackoverflow.com/questions/1744802/…
    • 介于 51 和 60 之间 - 包括在内。
    • 但这将首先选择全部,然后从该选择中只取 10 对吗?还是第一个查询/视图已经只有 10 个?
    【解决方案3】:

    LINQ to SQL 通过使用 ROW_NUMBER 窗口函数来实现这一点:

      SELECT a,b,c FROM 
       (SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
        FROM Table) t0
       WHERE to.row_number BETWEEN 1000 and 1100;
    

    这可行,但是需要从 ORDER BY 中生成 row_number 可能会导致您的查询在服务器端进行排序并导致性能问题。即使索引可以满足 ORDER BY 要求,查询仍然需要计算 1000 行才能开始返回结果。开发人员经常忘记这一点,只是对 5 百万行的表进行分页控制,并想知道为什么第一页的返回速度比最后一页快得多......

    不过,使用 ROW_NUMBER() 可能是易用性和良好性能之间的最佳平衡,前提是您确保避免排序(索引可以满足 ORDER BY 条件)。

    【讨论】:

    • 感谢您提供额外的性能信息,必须小心并进行测试。
    • 经过测试,对于我的 50 万行表,最后一页比第一页慢 7 倍。不理想,但对我来说可以接受。
    【解决方案4】:

    试试这个:

    select * from [Table-Name] order by [Column-Name] 
    offset [Skip-Count] rows
    FETCH NEXT [Take-Count] rows only
    

    例子:

    select * from Personals order by Id
    offset 10 rows            --------->Skip 10
    FETCH NEXT 15 rows only   --------->Take 15
    

    【讨论】:

      【解决方案5】:

      这样做:

      在 LINQ to SQL 数据上下文上运行 .Skip(1000).Take(100) 并查看 SQL 输出。它将为您生成一个 SQL 语句,执行您所描述的操作。

      它不会那么优雅,但它可以完成工作。

      【讨论】:

      • 不是被问到的。
      【解决方案6】:

      不,但您可以emulate MySQL's LIMIT clause(堆栈溢出链接)来获得相同的结果。

      【讨论】:

      猜你喜欢
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 2011-04-09
      • 1970-01-01
      相关资源
      最近更新 更多