Es gibt einen undokumentiertes Aggregat
namens ANY
Dies ist keine gültige Syntax, kann aber in Ihren Ausführungsplänen erscheinen. Dies bringt jedoch keinen Performance-Vorteil.
Unter der Annahme der folgenden Tabellen- und 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
Ich habe auch Beispieldaten so aufgefüllt, dass es viele Zeilen pro Gruppe gibt.
Ihre ursprüngliche Anfrage
SELECT MAX(id),
[group]
FROM T
GROUP BY [group]
Ergibt Table 'T'. Scan count 1, logical reads 1367
und der Plan
|--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([Expr1003]=MAX([[T].[id])))
|--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)
Umgeschrieben, um den ANY
zu erhalten aggregieren...
;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
Ergibt Table 'T'. Scan count 1, logical reads 1367
und der Plan
|--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([[T].[id]=ANY([[T].[id])))
|--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)
Auch wenn SQL Server möglicherweise die Verarbeitung der Gruppe stoppen könnte, sobald der erste Wert gefunden wird, und zum nächsten überspringt, tut dies dies nicht. Es verarbeitet immer noch alle Zeilen und die logischen Lesevorgänge sind die gleichen.
Für dieses spezielle Beispiel mit vielen Zeilen in der Gruppe wäre eine effizientere Version ein rekursiver 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);
Was gibt
Table 'Worktable'. Scan count 2, logical reads 19
Table 'T'. Scan count 4, logical reads 12
Die logischen Lesevorgänge sind viel geringer, da die erste Zeile pro Gruppe abgerufen wird und dann in der nächsten Gruppe gesucht wird, anstatt eine Menge Datensätze zu lesen, die nicht zum Endergebnis beitragen.