MSSQL中按分组+最大rowId获取每组最后一条记录的最优查询
解决SQL Server中按分组取每组最后一条记录(基于自增rowId)的最优方案
嘿,这个场景太常见了——用时间戳分组的时候,批量更新很容易导致同一组里多条记录的lastupdate完全一致,原查询就会返回重复结果。好在你有自增的rowId,这可是个精准定位的利器,结合它就能完美解决问题,还能保证性能。下面给你两种最优的实现方式,附性能优化建议:
方案一:分组子查询关联(适合追求极致性能的场景)
这种写法先通过分组拿到每个computername对应的最大rowId,再和原表关联匹配,精准定位每组的最后一条记录:
SELECT t.* FROM t INNER JOIN ( SELECT computername, MAX(rowId) AS max_rowId FROM t GROUP BY computername ) AS grouped_t ON t.computername = grouped_t.computername AND t.rowId = grouped_t.max_rowId;
性能说明:
只要给表t创建复合索引(computername, rowId),数据库就能直接通过索引快速获取每个分组的最大rowId,不需要扫描全表。这个索引还能加速后续的关联操作,整体性能非常出色。
方案二:ROW_NUMBER()窗口函数(可读性&灵活性拉满)
SQL Server 2005及以后支持窗口函数,这种写法可读性极强,而且如果之后需要取每组前N条记录,改个条件就行:
WITH ranked_records AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY computername ORDER BY rowId DESC) AS rn FROM t ) SELECT * FROM ranked_records WHERE rn = 1;
性能说明:
同样建议创建复合索引(computername, rowId DESC),数据库可以利用这个索引直接完成分组排序,避免额外的排序开销,效率和方案一不相上下,但代码更易懂。
关键注意点
- 确保
rowId是严格自增且不会被更新的:因为我们依赖它的递增性来判断“最后一条”,如果更新操作会修改rowId,这个逻辑就不成立了(不过自增字段默认是不会被修改的,放心用)。 - 索引是性能核心:上面提到的复合索引能让两种方案的查询速度提升几个量级,尤其是数据量大的时候,一定要加上。
内容的提问来源于stack exchange,提问作者onkami
相关产品推荐
相关产品推荐

