【问题标题】:SQL Server SELECT LAST N RowsSQL Server SELECT LAST N 行
【发布时间】:2011-05-10 18:31:43
【问题描述】:

这是一个已知问题,但我发现的最佳解决方案是:

SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

我有一张有很多行的表。使用该查询是不可能的,因为它需要很多时间。那么如何在不使用 ORDER BY 的情况下选择最后 N 行呢?

编辑

对不起this one的重复问题

【问题讨论】:

  • 最后一个N是什么意思?没有订单,“最后 N”没有多大意义。如果您的意思是“要插入的最后 N 个”,那么您不能依赖 SQL Server 将其提供给您 - 您必须使用 ORDER BY 子句。
  • @Daniel Renshaw:表的最后 N 个没有强制 SQL Server 对所有表进行排序,因为它真的很慢
  • 您问题中的查询最好的方法。如果 id 被索引,那么它只会反向扫描该索引并在前 5 行之后停止。如果它没有被索引,那么它需要做一个TOP N 排序。这不会比任何其他方式更糟糕。它不会对整个表进行排序(尽管它需要扫描整个表)
  • 你为什么用使用排序的分区标记答案作为接受的答案?它并不比您的原始查询更好。它所做的一切都为查询增加了细微差别 - 即特定客户的最后 N 个。您的查询不需要任何分区。

标签: sql sql-server performance sql-server-2008


【解决方案1】:

您可以使用以下查询让 SQL Server 选择最后 N 行:

select * from tbl_name order by id desc limit N;

【讨论】:

  • 版本兼容性如何?
  • 这在 SQL Server 中不起作用。看起来像是 MySQL、PostgreSQL 和 SQLite 功能。
  • 所有列举的产品都是 SQL 服务器。如果你想谈 MS SQL 服务器,为什么不这样命名呢?
  • 我很困惑,问题询问如何“不使用 ORDER BY”创建选择查询,并且您的答案中的选择查询具有“排序依据”。这是某种没有“order by”的“order by”吗?
  • @gena2x 这个问题被标记为 SQL Server。该标记指的是 Microsoft SQL Server。
【解决方案2】:

我测试了JonVD的代码,发现速度很慢,6s。

这段代码用了 0。

SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders where EmployeeID=5    
Order By OrderDate DESC

【讨论】:

  • 多少行??当你有很多行可能真的很慢时
  • @Diego 为什么会这样?如果您已将OrderDate 编入索引,那么选择查询的前或最后 N 行应该同样快。我意识到OrderDate 与插入的订单有很好的相关性,但这充其量只是一个副作用,仍然需要表扫描,不是吗? (而且我不认为它回答了 OP 指向 a better phrased dupe of their question 的内容:即,没有排序)
  • @Diego - 为什么你认为这会比你接受的答案慢?
  • 这会返回颠倒的行。然后,您必须通过他们重新订购才能取回原始订单。
【解决方案3】:

您也可以使用 ROW NUMBER BY PARTITION 功能来做到这一点。一个很好的例子可以找到here:

我正在使用 Northwind 数据库的 Orders 表...现在让我们检索员工 5 下的最后 5 个订单:

SELECT ORDERID, CUSTOMERID, OrderDate
FROM
(
    SELECT ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY OrderDate DESC) AS OrderedDate,*
    FROM Orders
) as ordlist

WHERE ordlist.EmployeeID = 5
AND ordlist.OrderedDate <= 5

【讨论】:

  • ROW NUMBER BY PARTITION 功能也使用了排序。您需要对表格进行排序,以便为每条记录分配行号...
  • 这是真的,但如果没有某种性质,这根本行不通,最好的解决方案是索引被命中的主要列并使用上述查询运行。
【解决方案4】:

如果您想从表格中选择最后几行。

语法类似于

 select * from table_name except select top 
 (numbers of rows - how many rows you want)* from table_name

这些语句有效,但方式不同。谢谢你们。

 select * from Products except select top (77-10) * from Products

这样你可以得到最后10行,但顺序会以递减方式显示

select top 10 * from products
 order by productId desc 

 select * from products
 where productid in (select top 10 productID from products)
 order by productID desc

 select * from products where productID not in 
 (select top((select COUNT(*) from products ) -10 )productID from products)

【讨论】:

    【解决方案5】:

    在一个非常一般的方式和支持SQL服务器这里是

    SELECT TOP(N) *
    FROM tbl_name
    ORDER BY tbl_id DESC
    

    而且对于性能来说,还不错(在服务器机器上超过 10,000 条记录不到一秒)

    【讨论】:

    • 好吧,10'000 条记录是您不应该关心性能的地方。当您开始谈论数百万条记录时,您就可以开始考虑性能
    【解决方案6】:

    首先你从

    获得记录数
     Declare @TableRowsCount Int
     select @TableRowsCount= COUNT(*) from <Your_Table>
    

    然后:

    在 SQL Server 2012 中

    SELECT *
    FROM  <Your_Table> As L
    ORDER BY L.<your Field>
    OFFSET <@TableRowsCount-@N> ROWS
    FETCH NEXT @N ROWS ONLY;
    

    在 SQL Server 2008 中

    SELECT *
    FROM 
    (
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS sequencenumber, *
    FROM  <Your_Table>
        Order By <your Field>
    ) AS TempTable
    WHERE sequencenumber > @TableRowsCount-@N 
    

    【讨论】:

      【解决方案7】:

      “Id”是否已编入索引?如果没有,那是一件很重要的事情(我怀疑它已经被索引了)。

      另外,您是否需要返回所有列?如果您实际上只需要一个较小的列子集,可以由 ID 列上的索引完全满足 - 例如,您可能能够大幅提高速度。如果您在 Id 列上有一个 NONCLUSTERED 索引,并且索引中不包含其他字段,那么它必须对聚集索引进行查找才能真正让其余列返回,这可能会占很多查询的成本。如果它是一个 CLUSTERED 索引,或者一个包含您要在查询中返回的所有其他字段的 NONCLUSTERED 索引,那么您应该没问题。

      【讨论】:

        【解决方案8】:

        您可以在没有order by 的情况下尝试以下操作,但我认为它要求每一行都是唯一的。 N 是你想要的行数,L 是表格的行数。

        select * from tbl_name except select top L-N * from tbl_name
        

        如前所述,返回哪些行是未定义的。

        编辑:这实际上是狗慢。真的没有价值。

        【讨论】:

          【解决方案9】:
          select * from (select top 6 * from vwTable order by Hours desc) T order by Hours
          

          【讨论】:

            【解决方案10】:

            MS 不支持 t-sql 中的 LIMIT。大多数时候我只是得到 MAX(ID) 然后减去。

            select * from ORDERS where ID >(select MAX(ID)-10 from ORDERS)
            

            当 ID 不连续时,这将返回少于 10 条记录。

            【讨论】:

              【解决方案11】:

              此查询以正确的顺序返回最后 N 行,但它的性能很差

              select *
              from (
                  select top N *
                  from TableName t
                  order by t.[Id] desc
              ) as temp
              order by temp.[Id]
              

              【讨论】:

                【解决方案12】:

                在查询末尾使用 desc 和 orderby 来获取最后的值。

                【讨论】:

                  【解决方案13】:

                  这可能不太适合这个问题,但是……

                  OFFSET 子句

                  OFFSET number 子句使您可以跳过 number 行,然后返回之后的行。

                  该文档链接指向 Postgres;我不知道这是否适用于 Sybase/MS SQL Server。

                  【讨论】:

                    【解决方案14】:
                    DECLARE @MYVAR  NVARCHAR(100)
                    DECLARE @step  int
                    SET @step = 0;
                    
                    
                    DECLARE MYTESTCURSOR CURSOR
                    DYNAMIC 
                    FOR
                    SELECT col FROM [dbo].[table]
                    OPEN MYTESTCURSOR
                    FETCH LAST FROM MYTESTCURSOR INTO @MYVAR
                    print @MYVAR;
                    
                    
                    WHILE @step < 10
                    BEGIN   
                        FETCH PRIOR FROM MYTESTCURSOR INTO @MYVAR
                            print @MYVAR;
                            SET @step = @step + 1;
                    END   
                    CLOSE MYTESTCURSOR
                    DEALLOCATE MYTESTCURSOR
                    

                    【讨论】:

                      【解决方案15】:

                      我用来查询超大表中最近行的一种技术(100+百万或1+十亿行)是有限制的查询仅“读取”最近“N”个百分比的 RECENT ROWS。这是现实世界的应用程序,例如,我对非历史近期天气数据、近期新闻提要搜索或近期 GPS 位置数据点数据执行此操作。

                      这是一个巨大的性能改进,例如,如果您确定自己的行位于表的最新 TOP 5% 中。这样即使表上有索引,它也将可能性进一步限制为只有 5% 的表中具有 100+ 百万或 1+ 十亿行的行。当较旧的数据需要 物理磁盘 读取而不仅仅是 Logical In Memory 读取时,情况尤其如此。

                      这比 SELECT TOP | 更有效百分比 | LIMIT 因为它不选择行,而只是限制要搜索的数据部分。

                      DECLARE @RowIdTableA BIGINT
                      DECLARE @RowIdTableB BIGINT
                      DECLARE @TopPercent FLOAT
                      
                      -- Given that there is an Sequential Identity Column
                      -- Limit query to only rows in the most recent TOP 5% of rows
                      SET @TopPercent = .05
                      SELECT @RowIdTableA = (MAX(TableAId) - (MAX(TableAId) * @TopPercent)) FROM TableA
                      SELECT @RowIdTableB = (MAX(TableBId) - (MAX(TableBId) * @TopPercent)) FROM TableB
                      
                      SELECT *
                      FROM TableA a
                      INNER JOIN TableB b ON a.KeyId = b.KeyId
                      WHERE a.Id > @RowIdTableA AND b.Id > @RowIdTableB AND
                            a.SomeOtherCriteria = 'Whatever'
                      

                      【讨论】:

                      • 一个有趣的方法
                      【解决方案16】:

                      我在使用 SQL Server 时遇到了这个问题 我为解决它所做的是将结果降序排列并为其结果提供行号,在我过滤结果并再次将它们翻转之后。

                        SELECT * 
                        FROM (
                          SELECT *
                                ,[rn] = ROW_NUMBER() OVER (ORDER BY [column] DESC)
                          FROM [table]
                        ) A 
                        WHERE A.[rn] < 3
                        ORDER BY [column] ASC
                      

                      简单的复制粘贴答案

                      【讨论】:

                        【解决方案17】:

                        不使用order by显示最后3行:

                        select * from Lms_Books_Details where Book_Code not in 
                         (select top((select COUNT(*) from Lms_Books_Details ) -3 ) book_code from Lms_Books_Details) 
                        

                        【讨论】:

                        • 这不会提供可预测的结果。根据 Sql Server MSDN 文档 (msdn.microsoft.com/en-us/library/ms189463.aspx):“当 TOP 与 ORDER BY 子句结合使用时,结果集限制为前 N 条有序行;否则,它返回前 N 条行以未定义的顺序。”
                        【解决方案18】:

                        尝试使用EXCEPT 语法。
                        像这样:

                           SELECT * 
                            FROM   clientDetails 
                            EXCEPT 
                            (SELECT TOP (numbers of rows - how many rows you want) * 
                             FROM   clientDetails) 
                        

                        【讨论】:

                        • 与@Prafulla Sutradhar 的答案相同
                        猜你喜欢
                        • 2016-01-11
                        • 2013-06-26
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-06-16
                        • 2012-01-23
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多