Preskočiť na obsah
Návod

Paralelizmus v pláne – Distribute, Repartition a Gather Streams

Paralelné operátory v pláne: Distribute, Repartition a Gather Streams, Partitioning Type, rozdelenie riadkov po vláknach (skew), exchange spill, NonParallelPlanReason a čakania CXPACKET / CXCONSUMER.

4 min čítania 3 kroky 1 obrázok SQL Server 2016+
> [!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

![Paralelné operátory a rozdelenie riadkov po vláknach](uploads/2026/11/plan-o12.svg "Exchange operátory presúvajú riadky medzi vláknami; nerovnomerné vlákna = skew")

V SSMS: operátor **Parallelism** s logickou operáciou **Distribute Streams**, **Repartition Streams** alebo **Gather Streams**. Operátory, ktoré bežia vo viacerých vláknach, majú pri ikone **žlté koliesko s dvoma šípkami**. Na SELECT je vlastnosť **Degree of Parallelism**.

## Čo to znamená

Paralelný plán rozdelí prácu medzi viac vlákien (*DOP* – degree of parallelism). Operátory **Parallelism** (*exchange*) prenášajú riadky medzi skupinami vlákien:

- **Distribute Streams** – z jedného vlákna do viacerých.
- **Repartition Streams** – z N vlákien do N vlákien, napr. aby riadky s rovnakým kľúčom skončili v tom istom vlákne pred spojením alebo agregáciou.
- **Gather Streams** – z viacerých vlákien do jedného (zvyčajne tesne pred SELECT).

### Do hĺbky

- **Partitioning Type** (F4 pri Repartition / Distribute) – *Hash*, *Round Robin*, *Broadcast* (malý vstup sa pošle každému vláknu), *Range*.
- **Order By** pri Gather Streams = *order-preserving exchange* – vlákna musia odovzdávať v poradí; pri nerovnomerných vláknach to brzdí.
- **Actual Number of Rows** pri paralelnom operátore sa dá rozbaliť **po vláknach**. Veľký nepomer = **skew**: jedno vlákno robí väčšinu práce, ostatné čakajú.
- Čakanie výmenníkov je **CXPACKET** a **CXCONSUMER** (rozdelené od 2016 SP2 / 2017 CU3), v novších verziách aj **CXSYNC_PORT** a **CXSYNC_CONSUMER** – viď [Čakania](waits.php#CXPACKET).
- **Exchange spill** – varovanie, keď výmenník nestíhal a musel riadky odložiť do tempdb (typicky pri order-preserving exchange, keď by sa vlákna navzájom zastavili).
- **NonParallelPlanReason** na SELECT povie, prečo plán **nemohol** byť paralelný (napr. skalárna funkcia, `MAXDOP 1`, table variable modifikácia).
- Paralelný plán sa zvažuje, keď odhadovaný náklad sériového plánu prekročí **cost threshold for parallelism** – viď [Paralelizmus – cost threshold, MAXDOP](script.php?id=93&s=paralelizmus-cost-threshold-maxdop-a-cxpacket-cxconsumer).

## Kedy je to v poriadku / kedy problém

| V poriadku | Problém |
|---|---|
| veľký report, vlákna rovnomerne vyťažené | malý OLTP dotaz s paralelným plánom (vysoký počet volaní) |
| CPU time > elapsed time (vlákna pracujú naraz) | skew – jedno vlákno má skoro všetky riadky |
| Gather Streams tesne pred SELECT | order-preserving Gather s exchange spillom |

## Ako si to vyskúšať

```sql
USE PlanLab;
SET STATISTICS TIME ON;

-- 1) Paralelný plán (ak má server viac jadier a náklad prekročí cost threshold)
SELECT ProductID, SUM(Qty * Price) AS trzba
FROM dbo.OrderLines
GROUP BY ProductID
OPTION (MAXDOP 4);

-- 2) Ten istý dotaz sériovo – porovnaj CPU time a elapsed time
SELECT ProductID, SUM(Qty * Price) AS trzba
FROM dbo.OrderLines
GROUP BY ProductID
OPTION (MAXDOP 1);

-- 3) Skew: zákazník 1 má 100 000 objednávok, ostatní pár kusov
SELECT o.CustomerID, SUM(l.Qty) AS kusy
FROM dbo.Orders AS o
JOIN dbo.OrderLines AS l ON l.OrderID = o.OrderID
GROUP BY o.CustomerID
OPTION (MAXDOP 4);
```

Spusti s **Include Actual Execution Plan** (Ctrl+M). Na SELECT pozri *Degree of Parallelism*, pri operátoroch rozbaľ *Actual Number of Rows* po vláknach. Ak plán ostane sériový, pozri na SELECT *NonParallelPlanReason* alebo nastavenie *cost threshold for parallelism* servera.

## Čo s tým

1. Paralelizmus je dobrý pre veľké dotazy. Rieš ho, keď **malé časté dotazy** idú paralelne (zvýš *cost threshold for parallelism*) alebo keď je **skew**.
2. Pri skew pozri dáta (jedna hodnota má väčšinu riadkov) a štatistiky; niekedy pomôže prepis dotazu alebo iný typ spojenia.
3. MAXDOP pre konkrétny dotaz meň hintom len výnimočne – nastavenie servera / databázy rieši recept [Paralelizmus – cost threshold, MAXDOP](script.php?id=93&s=paralelizmus-cost-threshold-maxdop-a-cxpacket-cxconsumer).

## Súvisiace

- [Paralelizmus – cost threshold, MAXDOP a CXPACKET](script.php?id=93&s=paralelizmus-cost-threshold-maxdop-a-cxpacket-cxconsumer)
- [Hash Match](script.php?id=73&s=hash-match-hash-join-a-hash-aggregate-build-a-probe)
- [Čakanie CXPACKET](waits.php#CXPACKET)
- [Čakanie CXCONSUMER](waits.php#CXCONSUMER)
- [Top 20 dotazov podľa CPU](script.php?id=5&s=top-20-dotazov-podla-cpu)

## Zdroje

- [Microsoft Learn – Showplan Logical and Physical Operators Reference](https://learn.microsoft.com/sql/relational-databases/showplan-logical-and-physical-operators-reference)
- [Microsoft Learn – Query Processing Architecture Guide](https://learn.microsoft.com/sql/relational-databases/query-processing-architecture-guide)
- [Microsoft Learn – Configure the max degree of parallelism](https://learn.microsoft.com/sql/database-engine/configure-windows/configure-the-max-degree-of-parallelism-server-configuration-option)
- [Hugo Kornelis – SQL Server Execution Plan Reference (SQLServerFast)](https://sqlserverfast.com/epr/)
- [Paul White – SQLkiwi (články o optimalizátore a operátoroch)](https://www.sql.kiwi/)

_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._