> [!TIP] > Recept z [kuchárky exekučných plánov](script.php?id=64&s=exekucne-plany-kucharka-zacni-tu). Ukážky bežia v testovacej databáze [PlanLab](script.php?id=65&s=planlab-testovacia-databaza-pre-recepty-exekucnych-planov) – nikdy ich nespúšťaj na produkcii. ## Ako to vyzerá v pláne  V SSMS: **Stream Aggregate** (ikona Σ) alebo **Hash Match** s logickou operáciou *Aggregate*. V paralelných plánoch často dva stupne: *Partial Aggregate* (lokálne v každom vlákne) a potom *Global* / finálna agregácia. ## Čo to znamená GROUP BY (aj DISTINCT, COUNT, SUM…) sa dá spočítať dvoma spôsobmi: - **Stream Aggregate** – vstup musí byť **zoradený podľa stĺpcov GROUP BY**. Operátor číta riadky a keď sa hodnota skupiny zmení, vydá súčet a začne novú skupinu. Netreba pamäť na skupiny, prvý výsledok ide hneď. - **Hash Aggregate** – vstup môže byť v ľubovoľnom poradí. Každá skupina má záznam v hash tabuľke v pamäti. Potrebuje **memory grant** a výsledky vydá až na konci (blokujúci). Bez GROUP BY (napr. `SELECT COUNT(*)`) je to v row mode vždy **Stream Aggregate** – jedna skupina (v batch mode môže byť aj Hash Match). ### Do hĺbky - Optimalizátor volí podľa toho, či zoradenie príde „zadarmo“ z indexu, a podľa **odhadu počtu skupín**. Pre málo skupín a veľa riadkov je hash lacný; pre zoradený vstup je stream lacnejší. - Niekedy vidíš **Sort + Stream Aggregate** – optimalizátor odhadol, že zoradiť a prúdiť je lacnejšie ako hash (často pri malom vstupe). - Zlý odhad počtu skupín → zlý grant pre Hash Aggregate → [spill](script.php?id=90&s=spill-do-tempdb-sort-a-hash-warning-memory-grant-feedback) (*Hash Warning*). - **Defined Values** (F4) ukážu, ktoré agregácie operátor počíta (napr. `Expr1002 = COUNT(*)`); ďalší **Compute Scalar** z nich často spraví výsledný stĺpec (napr. konverzia COUNT_BIG na int). - V batch mode je hash agregácia efektívna a SQL Server vie časť agregácie urobiť už pri čítaní columnstore (*aggregate pushdown*, [columnstore](script.php?id=81&s=columnstore-a-batch-mode-actual-execution-mode-segment-elimination)). ## Kedy je to v poriadku / kedy problém | V poriadku | Problém | |---|---| | Stream Aggregate nad indexom v správnom poradí | Sort miliónov riadkov len kvôli Stream Aggregate | | Hash Aggregate s malým počtom skupín | Hash Warning (spill) pri agregácii | | Partial + Global v paralelnom pláne | odhad skupín 10, skutočnosť 1 000 000 | ## Ako si to vyskúšať ```sql USE PlanLab; SET STATISTICS IO ON; -- 1) GROUP BY podľa stĺpca indexu → Stream Aggregate nad Index Scan (zoradený vstup) SELECT CustomerID, COUNT(*) AS objednavky FROM dbo.Orders GROUP BY CustomerID; -- 2) GROUP BY podľa stĺpca bez indexu, málo skupín → Hash Aggregate SELECT Status, COUNT(*) AS objednavky FROM dbo.Orders GROUP BY Status; -- 3) Skalárna agregácia (bez GROUP BY) → v row mode Stream Aggregate SELECT COUNT(*), SUM(Amount) FROM dbo.Orders; -- 4) Veľa skupín bez indexu (pozri Memory Grant Info a prípadné Partial Aggregate pri paralelizme) SELECT ProductID, OrderID % 1000 AS bucket, SUM(Qty) FROM dbo.OrderLines GROUP BY ProductID, OrderID % 1000; ``` Spusti s **Include Actual Execution Plan** (Ctrl+M). Pri Stream Aggregate pozri, či je pred ním Sort; pri Hash Match (Aggregate) odhad a skutočný počet riadkov na výstupe (= počet skupín). ## Čo s tým 1. Častý GROUP BY na veľkej tabuľke: index so stĺpcami GROUP BY na začiatku kľúča umožní Stream Aggregate bez Sort. 2. Pri spille Hash Aggregate rieš odhad počtu skupín (štatistiky na stĺpcoch GROUP BY, viacstĺpcové štatistiky). 3. Analytické agregácie miliónov riadkov: [columnstore a batch mode](script.php?id=81&s=columnstore-a-batch-mode-actual-execution-mode-segment-elimination). ## Súvisiace - [Hash Match](script.php?id=73&s=hash-match-hash-join-a-hash-aggregate-build-a-probe) - [Sort, Top a Top N Sort](script.php?id=75&s=sort-top-a-top-n-sort-zoradovanie-a-pamat) - [Spill do tempdb](script.php?id=90&s=spill-do-tempdb-sort-a-hash-warning-memory-grant-feedback) - [Columnstore a batch mode](script.php?id=81&s=columnstore-a-batch-mode-actual-execution-mode-segment-elimination) ## Zdroje - [Microsoft Learn – Showplan Logical and Physical Operators Reference](https://learn.microsoft.com/sql/relational-databases/showplan-logical-and-physical-operators-reference) - [Hugo Kornelis – SQL Server Execution Plan Reference (SQLServerFast)](https://sqlserverfast.com/epr/) - [Grant Fritchey – SQL Server Execution Plans, 3. vydanie (Redgate, e-kniha zadarmo)](https://www.red-gate.com/simple-talk/books/sql-server-execution-plans-third-edition/) _Texty sú vlastné, tvrdenia overené proti uvedeným zdrojom (11/2026). T-SQL je staticky skontrolovaný, nie spustený na živom serveri – vyskúšaj ho najprv v PlanLab._
Stream Aggregate vs. Hash Aggregate – GROUP BY v pláne
Ako SQL Server počíta GROUP BY a DISTINCT: Stream Aggregate na zoradenom vstupe vs. Hash Aggregate s memory grantom, Partial Aggregate v paralelnom pláne a Sort pred agregáciou.