Det finns en odokumenterat aggregat
kallas ANY
som inte är giltig syntax men är möjlig att få synas i dina körplaner. Detta ger dock ingen prestandafördel.
Om vi antar följande tabell- och indexstruktur
CREATE TABLE T
(
id int identity primary key,
[group] char(1)
)
CREATE NONCLUSTERED INDEX ix ON T([group])
INSERT INTO T
SELECT TOP 1000000 CHAR( 65 + ROW_NUMBER() OVER (ORDER BY @@SPID) % 3)
FROM sys.all_objects o1, sys.all_objects o2, sys.all_objects o3
Jag har också fyllt på med exempeldata så att det finns många rader per grupp.
Din ursprungliga fråga
SELECT MAX(id),
[group]
FROM T
GROUP BY [group]
Ger Table 'T'. Scan count 1, logical reads 1367
och planen
|--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([Expr1003]=MAX([[T].[id])))
|--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)
Skrivs om för att få ANY
sammanställt...
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY [group] ORDER BY [group] ) AS RN
FROM T)
SELECT id,
[group]
FROM cte
WHERE RN=1
Ger Table 'T'. Scan count 1, logical reads 1367
och planen
|--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([[T].[id]=ANY([[T].[id])))
|--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)
Även om SQL Server potentiellt kan sluta bearbeta gruppen så snart det första värdet hittas och hoppa till nästa gör det inte det. Den bearbetar fortfarande alla rader och de logiska läsningarna är desamma.
För detta specifika exempel med många rader i gruppen skulle en mer effektiv version vara en rekursiv CTE.
WITH RecursiveCTE
AS (
SELECT TOP 1 id, [group]
FROM T
ORDER BY [group]
UNION ALL
SELECT R.id, R.[group]
FROM (
SELECT T.*,
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM T
JOIN RecursiveCTE R
ON R.[group] < T.[group]
) R
WHERE R.rn = 1
)
SELECT *
FROM RecursiveCTE
OPTION (MAXRECURSION 0);
Vilket ger
Table 'Worktable'. Scan count 2, logical reads 19
Table 'T'. Scan count 4, logical reads 12
De logiska läsningarna är mycket mindre eftersom den hämtar den första raden per grupp och sedan söker in i nästa grupp snarare än att läsa en mängd poster som inte bidrar till det slutliga resultatet.