在单表扫描、没有窗口函数、单个group by的情况下,如果没有重复日期的问题,与窗口函数相比性能相同,甚至在处理大型查询时性能更好。 (更新:我不知道它与TOP 1 WITH TIES / CROSS APPLY方法相比的性能如何。由于它使用了扫描,因此在某些情况下可能会更慢。)
SELECT
LogEntryID = Convert(int, Substring(Packed, 9, 4)),
FileID = Convert(int, Substring(Packed, 13, 4)),
CreatedOn = Convert(datetime, Substring(Packed, 1, 8)),
EventTypeID = Convert(int, Substring(Packed, 17, 4))
FROM
(
SELECT
Packed = Max(
Convert(binary(8), CreatedOn)
+ Convert(binary(4), LogEntryID)
+ Convert(binary(4), FileID)
+ Convert(binary(4), EventTypeID)
)
FROM LogEntries
WHERE EventTypeID IN (2,4)
GROUP BY ClientName
) X
如果有人想看这个操作的实际效果,以下是一些创建脚本:
USE tempdb
CREATE TABLE LogEntries (
LogEntryID int not null identity(1,1),
FileID int,
CreatedOn datetime,
EventTypeID int,
ClientName varchar(30)
)
INSERT LogEntries VALUES (1, GetDate()-20, 2, 'bob')
INSERT LogEntries VALUES (1, GetDate()-19, 3, 'bob')
INSERT LogEntries VALUES (1, GetDate()-18, 4, 'bob')
INSERT LogEntries VALUES (1, GetDate()-17, 3, 'bob')
INSERT LogEntries VALUES (1, GetDate()-19.5, 2, 'anna')
INSERT LogEntries VALUES (1, GetDate()-18.5, 3, 'anna')
INSERT LogEntries VALUES (1, GetDate()-17.5, 4, 'anna')
INSERT LogEntries VALUES (1, GetDate()-16.5, 3, 'anna')
请注意,此方法利用了给定数据类型的内部字节表示方式,其排序与类型值相同。像float或decimal这样的打包数据类型将无法工作:这些类型需要首先转换为适当的int、bigint或character等类型。
此外,在SQL 2008中的新日期和时间数据类型具有不同的表示形式,无法正确打包以与此方法一起使用。我还没有检查Time数据类型,但对于Date数据类型:
DECLARE @d date
SET @d ='99990101'
SELECT Convert(binary(3), @d)
实际值为0x37B86E,因此它以相反的字节顺序存储它们(“零”日期是0001-01-01)。