在SQL中获取特定记录列表的最新版本的最佳方法

时间:2015-02-02 15:55:02

标签: sql sql-server

我想查询一个巨型表(SQL Server)以获取一组记录的最新版本,例如

表:

Id, key, Ver
1, A, 1
2, B, 1
3, A, 2
4, B, 2
5,B, 3

结果:

Id, Key, Ver
3, A, 2
5, B, 3

here中提到的连接方法可以正常工作,但只有在想要获取所有密钥的最新版本时才能正常工作,但如果我们只关心密钥子集,则连接将成为过多的开销。所以我想问一下我们是否应该进行循环

select top 1 * from table where key = 'A' order by ver desc

select max(ver), key from table where key in ('A', 'B') group by key

还是有更好的方法呢?欢呼声

5 个答案:

答案 0 :(得分:2)

基本上,一次一个地循环一组键并执行n次操作对于任何RDBMS都是一种糟糕的方法。它阻止查询引擎优化并保证n搜索\扫描表\索引。

如果您可以将查询表达为基于集合的操作,这将允许查询引擎完全优化您的操作,从而创建更加优化的查询计划。

如果您使用的是SQL Server 2008或更高版本,请使用RANK

SELECT
            [Id],
            [Key],
            [Ver]
    FROM
            [Table]
    WHERE
            RANK() OVER (PARTITION BY [Key], ORDER BY [Ver] DESC) = 1;

使用更通用的SQL,

SELECT
            [T1].[Id],
            [T2].[Key],
            [T2].[Ver]
    FROM (
            SELECT
                        [Key]
                        MAX([Ver]) [Ver]
                FROM
                        [Table]
                WHERE
                        [Key] IN ('A', 'B')
                GROUP BY
                        [Key]) [T2]
        JOIN
            [Table] [T1]
                ON [T1].[Key] = [T2].[Key] AND [T1].[Ver] = [T2].[Ver];

要确保两个查询的效果,请在Key然后Ver上创建覆盖索引。

CREATE UNIQUE NONCLUSTERED INDEX [IX_Table_Key_Ver]
    ON [Table] ([Key], [Ver] DESC);

答案 1 :(得分:0)

使用子选项查找密钥的最大值:

select * from table t1
where ver = (select max(ver) from table
             where key = t1.key)

答案 2 :(得分:0)

IMO,你的第二个解决方案应该表现得好,如果不是比这里提到的任何其他解决方案更好。

select max(ver), key from table where key in ('A', 'B') group by key

另外,在key列上创建索引。

编辑:

对于Max version row ID值,您可以使用CTE

WITH CTE AS
(
    select max(ver) VER, key from table where key in ('A', 'B') group by key
)
SELECT * FROM TABLE 
INNER JOIN CTE 
ON CTE.KEY=TABLE.KEY
AND CTE.VER=TABLE.VER

答案 3 :(得分:0)

这是另一种使用分析函数的方法,例如row_number

select * 
from (
  select *, row_number() over (partition by key order by id desc) rn
  from yourtable
  ) t
where rn = 1

答案 4 :(得分:0)

一般不要使用TOP 1的判断,ROW_NUMBER()更好。游标也不是一个好主意(忽略我的订单的技术性!)。

E.g。

SELECT
    A.*
FROM
    (
    SELECT
        ID
        ,Ver
        ,ROW_NUMBER() OVER(PARTITION BY Key ORDER BY Ver DESC) AS Seq
    FROM
        Table
    ) AS A
WHERE
    A.Seq = 1

应该做得很好,我相信你的要求。