如何有效地获取最近插入的每个值的记录

时间:2013-10-26 16:14:22

标签: sql sql-server sql-server-2008 tsql

我有一个表TableA,数据如下:

PostID   PostComments   PostTransDate                    UserID
-----------------------------------------------------------------
10000    VRDFHFGFTR     2013-10-26 21:08:19.817          43434
10000    GFDGDFSDFF     2013-10-26 21:12:32.323          67576
10000    HGFHGFBNBF     2013-10-26 21:43:43.545          3232
10000    JNFNGHFGHG     2013-10-26 21:45:46.656          768
10000    MJHJNGJHGH     2013-10-26 21:56:32.767          9897
10001    XCVGFDGDFG     2013-10-26 22:54:54.868          3424
10001    YTUGFGHHGF     2013-10-26 13:32:54.132          12313
10001    HGFHFGHGHF     2013-10-26 18:08:32.878          6565

在此,我想获得每个UserID,PostComments最大PostID值的PostTransDate

需要输出:

--------------------------------------------------
PostID   PostComments   PostTransDate                    UserID
-----------------------------------------------------------------
10000    MJHJNGJHGH     2013-10-26 21:56:32.767          9897
10001    XCVGFDGDFG     2013-10-26 22:54:54.868          3424

我已经有了获得此问题的疑问。

查询1:

SELECT  TT.PostID,TT.PostComments,TT.UserID, TT.PostTransDate
FROM tableA TT WITH(NOLOCK) 
INNER JOIN
(
    SELECT PostID,MAX(PostTransDate)  PostTransDate
    FROM tableA T WITH(NOLOCK)
    GROUP BY PostID 
) T ON T.PostID = TT.PostID AND T.PostTransDate = TT.PostTransDate 

查询2:

SELECT *
FROM
(
SELECT PostID,UserID,PostTransDate,T.PostComments,
        ROW_NUMBER() OVER(PARTITION BY PostID ORDER BY PostTransDate DESC) RNO
FROM tableA T

) N WHERE RNO = 1

我无法在生产中运行这些查询,因为这些查询非常繁重。如果有人有比此更简化的查询,请发帖。

2 个答案:

答案 0 :(得分:4)

不了解您的基础索引结构,以及您是否可以更改它,我建议使用此索引:

CREATE INDEX x ON dbo.TableA(PostID, PostTransDate DESC) 
  INCLUDE (UserID, PostComments);

这仍然需要扫描来解决现有查询,但它至少会扫描这个索引,这比扫描整个表更有效(假设表中还有其他列未被此引用查询)。

;WITH x AS 
(
  SELECT PostID, UserID, PostTransDate, PostComments,
    rn = ROW_NUMBER() OVER (PARTITION BY PostID ORDER BY PostTransDate DESC)
  FROM dbo.TableA
)
SELECT PostID, UserID, PostTransDate, PostComments
  FROM x WHERE rn = 1;

如果您想要包含关系(不同用户同时在同一帖子上发表多条评论),只需将ROW_NUMBER()更改为DENSE_RANK()(实际上,如果您只是追求过最新的日期,您可以有效地使用RANK() - 我不确定它们是否有任何不同,但它会为您节省6个字符)。如果您不想包含关系,可以通过在OVER()内添加一个额外的列来预测它们 - 例如,如果您希望用户具有最长的任期,您可以通过{在降序发布日期之后{1}}。

另一个想法是,如果你不能改变索引或者这没有提供足够的提升,那就是在另一个表中实现结果。您可以使用触发器轻松处理此问题,但它会影响您的DML工作负载,因此您不应该只修复此查询。它实际上可能会使您的应用程序性能变差。当然,除非您在此表中实现此查询的所有数据(并且这将是非常多余的),否则它可能无法正常工作,因为为了从主表中检索数据,您仍然必须加入到它,你仍然可能需要在较大的表上进行扫描才能这样做。如果主表有一个IDENTITY列或一些其他主键,这可能会使事情变得更容易和更有效,但在完全理解底层结构之前,我不打算开始编写解决方案。

答案 1 :(得分:1)

试试这个:

SELECT ta1.* FROM tableA ta1
LEFT JOIN tableA ta2
ON ta1.postId = ta2.postId AND ta1.postTransDate < ta2.postTransDate
WHERE ta2.postTransDate IS NULL

输出:

| POSTID | POSTCOMMENTS |                  POSTTRANSDATE | USERID |
|--------|--------------|--------------------------------|--------|
|  10000 |   MJHJNGJHGH | October, 26 2013 21:56:32+0000 |   9897 |
|  10001 |   XCVGFDGDFG | October, 26 2013 22:54:54+0000 |   3424 |

FIddle here