Preskočiť na obsah
Návod

Rebuild vs. reorganize indexov – rozdiel, kedy ktorý a vplyv na veľké databázy

Čím sa líši ALTER INDEX REBUILD od REORGANIZE (zámky, log, štatistiky, miesto, prerušenie), kedy ktorý použiť a prečo, čo urobí údržba indexov s veľkou databázou (transaction log, Always On, zálohy, tempdb, blokovanie), online a resumable rebuild, partície, columnstore, rozumné nastavenie IndexOptimize a typické pasce.

15 min čítania 9 krokov SQL Server 2016+
Oba príkazy riešia to isté – index, ktorý sa zmenami dát „rozsypal“ (stránky nie sú v poradí, sú poloprázdne). Robia to ale úplne inak a na veľkej databáze je rozdiel medzi nimi rozdiel medzi pokojnou nocou a incidentom ráno: plný LOG disk, zaostávajúca AG replika alebo tabuľka zamknutá na hodinu.

> [!CAUTION]
> Nespúšťaj na produkcii „rebuild všetkého“ len preto, že je noc. Na **Standard** edícii je každý rebuild **offline** – tabuľka je počas neho nedostupná. Aj na Enterprise vygeneruje rebuild veľkého indexu toľko logu, koľko má index, a log sa do konca operácie neoreže.

## V skratke

| | REORGANIZE | REBUILD |
|---|---|---|
| Čo robí | preusporiada a zhustí **listové** stránky existujúceho indexu, na mieste | postaví **novú kópiu** indexu (všetky úrovne), starú potom zahodí |
| Dostupnosť tabuľky | vždy online, žiadne dlhé zámky na úrovni tabuľky | **offline:** zámok `Sch-M` na tabuľke počas celej operácie; **online** (len Enterprise): krátky zámok na začiatku a na konci |
| Paralelizmus | vždy jedno vlákno | áno (paralelne len Enterprise), `MAXDOP` |
| Štatistiky | **neaktualizuje** | štatistiku indexu prepočíta ako `FULLSCAN` (pri partíciovanom alebo resumable rebuilde len vzorkou); stĺpcové štatistiky nie |
| Fill factor, kompresia | zhustí stránky na **existujúci** fill factor | môžeš zmeniť `FILLFACTOR`, `DATA_COMPRESSION`, presunúť index |
| Prerušenie / KILL | hotová práca **ostáva** | rollback celej operácie (okrem `RESUMABLE`) – môže trvať dlho |
| Miesto navyše | pár pracovných stránok v tom istom dátovom súbore | **druhá kópia** indexu + miesto na triedenie (+ mapping index pri online rebuilde clustered indexu) |
| Transaction log | veľa malých transakcií – log sa dá medzitým zálohou orezať | jedna transakcia – log sa **neoreže až do konca** (okrem `RESUMABLE`); v SIMPLE / BULK_LOGGED môže byť minimálne logovaný |
| Nedá sa použiť | heap, zakázaný index, `ALLOW_PAGE_LOCKS = OFF` | offline / read-only filegroup; online nie na každý typ indexu |

Microsoft v dokumentácii píše, že reorganize je menej náročný a má byť **preferovanou metódou, ak nie je konkrétny dôvod na rebuild**.

## Čo vlastne meriaš: fragmentácia vs. hustota stránok

- **Fragmentácia** (`avg_fragmentation_in_percent`) – logické poradie stránok podľa kľúča nesedí s fyzickým. Vadí hlavne veľkým rozsahovým scanom z disku, kde úložisko číta sekvenčne rýchlejšie ako náhodne. Na SSD / all-flash SAN je jej vplyv výrazne menší.
- **Hustota stránok** (`avg_page_space_used_in_percent`) – ako plné sú stránky. Po page splitoch a mazaní je index „nafúknutý“: viac stránok = viac I/O, viac miesta na disku **aj v buffer poole**. Podľa dokumentácie má zvýšenie hustoty v mnohých workloadoch väčší prínos ako odstránenie fragmentácie.
- Malé indexy (menej ako ~1000 stránok) neriešiš – rozdiel nebude merateľný.
- Prahy **5 % / 30 %** (reorganize / rebuild), ktoré používa aj recept [Fragmentácia indexov](script.php?id=4&s=fragmentacia-indexov) a predvolené nastavenie IndexOptimize, sú len historický východiskový bod. Aktuálna dokumentácia Microsoftu fixné prahy výslovne neodporúča – rozhoduje workload a cena údržby.

```sql
-- Fragmentácia a hustota stránok jednej tabuľky.
-- SAMPLED číta dátové stránky (LIMITED hustotu nevráti) – na veľkej DB ho nespúšťaj na všetky tabuľky naraz.
SELECT OBJECT_SCHEMA_NAME(ips.object_id)                        AS schema_name,
       OBJECT_NAME(ips.object_id)                               AS table_name,
       i.name                                                   AS index_name,
       ips.partition_number,
       ips.index_type_desc,
       ips.page_count,
       CAST(ips.page_count * 8 / 1024.0 AS decimal(18,1))       AS size_mb,
       CAST(ips.avg_fragmentation_in_percent AS decimal(5,1))   AS fragmentation_pct,
       CAST(ips.avg_page_space_used_in_percent AS decimal(5,1)) AS page_density_pct,
       i.fill_factor,
       i.allow_page_locks
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.MojaTabulka'), NULL, NULL, 'SAMPLED') AS ips
JOIN sys.indexes AS i ON i.object_id = ips.object_id AND i.index_id = ips.index_id
WHERE ips.alloc_unit_type_desc = N'IN_ROW_DATA'
  AND ips.page_count >= 1000
ORDER BY ips.page_count DESC;
```

## Prečo rebuild „pomohol“ – často sú to štatistiky

Klasický príbeh: dotaz bol pomalý, po nočnom rebuilde je rýchly, takže „fragmentácia bola problém“. Rebuild ale zároveň prepočíta štatistiku indexu s `FULLSCAN` a dotazy nad tabuľkou dostanú nový plán. Veľmi často pomohli **čerstvé štatistiky**, nie usporiadané stránky – a to isté dosiahneš za zlomok ceny cez `UPDATE STATISTICS`.

1. Keď rebuild „pomáha“, skús ho nahradiť aktualizáciou štatistík – [Štatistiky – posledný update a počet zmien](script.php?id=29&s=statistiky-posledny-update-a-pocet-zmien), [Zlé odhady riadkov](script.php?id=84&s=zle-odhady-riadkov-odhad-vs-skutocnost-a-statistiky).
2. Meraj pred a po údržbe cez Query Store – [Query Store – regresie](script.php?id=26&s=query-store-regresie-24-h-vs-predoslych-24-h) a [Query Store – top dotazy podľa CPU](script.php?id=25&s=query-store-top-dotazy-podla-cpu). Bez merania nevieš, či údržba niečo prináša.
3. Údržbu rob tam, kde je dôvod (indexy používané dotazmi so zhoršeným výkonom, výrazne nízka hustota), nie plošne – [Používanie indexov](script.php?id=27&s=pouzivanie-indexov-seeks-scans-lookups-updates) ukáže, ktoré indexy sa vôbec čítajú.

## Kedy ktorý

| Situácia | Voľba | Prečo |
|---|---|---|
| Bežná údržba, hustota alebo fragmentácia sa zhoršila, tabuľka sa počas dňa používa | **REORGANIZE** | online, prerušiteľný, log sa dá priebežne orezávať |
| Standard edícia, tabuľku nesmieš zamknúť | **REORGANIZE** (+ `UPDATE STATISTICS`) | rebuild by bol offline |
| Veľmi nízka hustota / vysoká fragmentácia veľkého indexu, reorganize by bežal hodiny | **REBUILD ONLINE** (Enterprise), ideálne `RESUMABLE` | paralelne, celý index naraz, dá sa pozastaviť |
| Chceš zmeniť fill factor, kompresiu, presunúť index na inú filegroup | **REBUILD** | reorganize tieto voľby nemá |
| Staging tabuľka po ETL, nikto ju práve nečíta | **REBUILD offline** | offline je rýchlejší ako online |
| Poškodený nonclustered index (CHECKDB, `index_id > 1`) | **REBUILD** alebo DROP + CREATE | [CHECKDB našiel chybu](script.php?id=61&s=checkdb-nasiel-chybu-co-dalej-823-824-825) |
| Heap s veľa forwarded records | `ALTER TABLE … REBUILD` | heap sa reorganizovať nedá |
| Columnstore index | **REORGANIZE** (`COMPRESS_ALL_ROW_GROUPS = ON`) | robí podstatu rebuildu online |
| Dotaz je rýchly „len po rebuilde“ | **UPDATE STATISTICS** | viď vyššie |

## Vplyv na veľké databázy

### Transaction log

- Rebuild vo **FULL** recovery modeli zapíše do logu rádovo celý index. Je to jedna transakcia, takže log sa **neoreže, kým rebuild neskončí** – log backupy počas neho bežať môžu (a majú), ale miesto neuvoľnia. Log musí uniesť rebuild **aj** bežnú prevádzku počas neho.
- `ALTER INDEX ALL … REBUILD` robí všetky indexy tabuľky v **jednej transakcii** – na veľkej tabuľke je to súčet všetkých indexov naraz.
- Reorganize beží v malých transakciách, log sa medzi log backupmi oreže. Pri veľmi fragmentovanom veľkom indexe ale môže vygenerovať aj **viac logu ako rebuild** (presúva stránky po jednej a všetko je plne logované).
- `RESUMABLE` rebuild podľa dokumentácie spotrebuje menej logu a log sa dá počas operácie orezať.
- `SORT_IN_TEMPDB = ON` presunie triedenie aj jeho log do tempdb – log používateľskej DB sa potom dá orezávať, ale tempdb (dáta aj log) musí uniesť najväčší index.
- Prepnutie na BULK_LOGGED kvôli minimálnemu logovaniu: log backup s minimálne logovanou operáciou je aj tak veľký (obsahuje zmenené extenty) a v jeho rozsahu stratíš obnovu k bodu v čase. V Always On to nejde vôbec (AG vyžaduje FULL).
- Pred veľkou údržbou: [Transaction log – obsadenie, reuse wait a VLF](script.php?id=33&s=transaction-log-obsadenie-reuse-wait-a-vlf), počas nej častejšie log backupy. Keď je neskoro: [LOG disk je plný](script.php?id=58&s=log-disk-je-plny-co-robit-krok-za-krokom-chyba-9002).

### Always On, log shipping, replikácia

- Celý log z údržby ide na **všetky repliky**. Rastie `log_send_queue` a `redo_queue`, pri synchrónnom commite čaká primárka na sekundárky ([HADR_SYNC_COMMIT](waits.php#HADR_SYNC_COMMIT)) a spomalí sa aj bežná prevádzka. Failover počas údržby alebo tesne po nej trvá dlhšie (sekundárka dobieha redo).
- Na **čitateľnej sekundárke** môže dlhý report zablokovať redo – rebuild potrebuje na replike rovnaký `Sch-M` zámok – a replika zaostáva ďalej.
- Údržba beží len na primárke a zmena sa replikuje logom – „spustiť rebuild na sekundárke“ nejde.
- Sleduj počas údržby [Always On AG – stav replík](script.php?id=42&s=always-on-ag-stav-replik-a-synchronizacie). Pri problémoch: nižší `MAXDOP`, menšie dávky (index po indexe, partícia po partícii), `@Delay` v IndexOptimize medzi príkazmi.
- Log shipping: obrovské log backupy, dlhý copy aj restore na sekundárke. Transakčná replikácia a CDC: Log Reader musí celý log prečítať – rastie latencia.

### Zálohy

- Rebuild zapisuje index do nových extentov, takže najbližšia **DIFF záloha** obsahuje celý prebudovaný index – po „rebuilde všetkého“ je DIFF takmer taký veľký ako FULL. Reorganize zväčší DIFF úmerne počtu presunutých stránok.
- Log backupy počas a po údržbe sú veľké – počítaj s tým v kapacite úložiska záloh a v čase kopírovania mimo server. Kontrola: [História záloh](script.php?id=31&s=historia-zaloh-typ-velkost-kompresia-subor).
- Údržbu neplánuj súbežne s FULL zálohou ani s CHECKDB – bojujú o to isté I/O.

### Miesto v dátových súboroch a tempdb

- Počas rebuildu existuje **stará aj nová kópia** indexu; stará sa uvoľní až po commite. Rebuild clustered indexu s 500 GB potrebuje vo filegroup ďalších ~500 GB na novú kópiu a k tomu miesto na triedenie (vo filegroup, alebo v tempdb pri `SORT_IN_TEMPDB = ON`). Bez miesta súbor narastie – a voľné miesto po rebuilde v ňom ostane.
- **Online** rebuild navyše: verzie riadkov meniacich sa počas operácie idú do **version store v tempdb** ([Version store – kto ho drží](script.php?id=57&s=version-store-kto-ho-drzi), [Kto spotrebúva tempdb](script.php?id=20&s=kto-spotrebuva-tempdb)), pri clustered indexe ešte dočasný mapping index s jedným riadkom na každý riadok tabuľky.
- Reorganize potrebuje voľné miesto v **tom istom dátovom súbore** (pracovné stránky alokuje len tam).
- Veľkosť najväčších indexov pred údržbou:

```sql
SELECT TOP (20)
       OBJECT_SCHEMA_NAME(ps.object_id)                         AS schema_name,
       OBJECT_NAME(ps.object_id)                                AS table_name,
       i.name                                                   AS index_name,
       i.type_desc,
       COUNT(*)                                                 AS partitions,
       SUM(ps.row_count)                                        AS row_count,
       CAST(SUM(ps.used_page_count) * 8 / 1024.0 AS decimal(18,1)) AS used_mb
FROM sys.dm_db_partition_stats AS ps
JOIN sys.indexes AS i ON i.object_id = ps.object_id AND i.index_id = ps.index_id
WHERE OBJECTPROPERTY(ps.object_id, 'IsMsShipped') = 0
GROUP BY ps.object_id, i.index_id, i.name, i.type_desc
ORDER BY used_mb DESC;
```

### Zámky a blokovanie

- **Offline rebuild** drží `Sch-M` zámok na tabuľke počas celej operácie – všetky dotazy na tabuľku čakajú ([LCK_M_SCH_S](waits.php#LCK_M_SCH_S)).
- **Online rebuild** potrebuje krátky zámok na začiatku a `Sch-M` na konci (výmena starej a novej štruktúry). Na ten musí počkať, kým dobehnú bežiace dotazy a transakcie – a kým čaká ([LCK_M_SCH_M](waits.php#LCK_M_SCH_M)), všetky **nové** dotazy na tabuľku čakajú za ním. Jeden dlhý report tak cez „online“ rebuild zastaví celú aplikáciu. Riešenie je `WAIT_AT_LOW_PRIORITY` (nižšie).
- Počas online rebuildu sa každá zmena dát zapisuje do starej aj novej kópie indexu – zápisy sú pomalšie.
- Pri problémoch: [Kto koho blokuje](script.php?id=1&s=kto-koho-blokuje-blocking-chain).

### CPU, I/O a buffer pool

Rebuild prečíta celý index a zapíše nový – na veľkých tabuľkách to vytlačí z buffer poolu „teplé“ dáta a ráno je server pomalší, kým sa cache znova nenaplní. Paralelný rebuild zaberie toľko jadier, koľko mu dovolí `MAXDOP` – pri údržbe cez deň ho obmedz.

## Online a resumable rebuild (Enterprise)

Online a resumable operácie sú podľa porovnania edícií len v **Enterprise** (a Developer / Evaluation) – platí to aj pre SQL Server 2025 Standard. Na Standard skončí `ONLINE = ON` chybou 1712.

```sql
-- Online rebuild, ktorý nezablokuje aplikáciu: na zámok čaká s nízkou prioritou 5 minút, potom to vzdá
ALTER INDEX IX_Orders_OrderDate ON dbo.Orders
REBUILD WITH (ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 5 MINUTES, ABORT_AFTER_WAIT = SELF)),
              MAXDOP = 4);

-- Resumable rebuild (2017+): po 2 hodinách sa sám pozastaví, pokračuješ ďalšiu noc
ALTER INDEX PK_Orders ON dbo.Orders
REBUILD WITH (ONLINE = ON, RESUMABLE = ON, MAX_DURATION = 120 MINUTES, MAXDOP = 4);

ALTER INDEX PK_Orders ON dbo.Orders PAUSE;
ALTER INDEX PK_Orders ON dbo.Orders RESUME WITH (MAXDOP = 2);
ALTER INDEX PK_Orders ON dbo.Orders ABORT;   -- ak ho už nechceš dokončiť

-- Stav resumable operácií v aktuálnej databáze
SELECT OBJECT_SCHEMA_NAME(object_id) AS schema_name, OBJECT_NAME(object_id) AS table_name, name AS index_name,
       partition_number, state_desc, CAST(percent_complete AS decimal(5,1)) AS percent_complete,
       start_time, last_pause_time, total_execution_time AS total_minutes, page_count
FROM sys.index_resumable_operations;
```

- `ABORT_AFTER_WAIT`: `SELF` = rebuild to vzdá, `BLOCKERS` = zabije blokujúce transakcie (vyžaduje `ALTER ANY CONNECTION` – na produkcii len vedome), `NONE` = čaká ďalej normálne.
- **Pozastavený** resumable rebuild nie je zadarmo: drží miesto rozpracovaného indexu, každá zmena dát udržiava obe kópie a ghost cleanup na novom indexe stojí. Ak ho nedokončíš, daj `ABORT`, nie len `PAUSE`.
- Resumable nejde: s `SORT_IN_TEMPDB = ON`, v explicitnej transakcii, pre `REBUILD ALL`, `ALTER TABLE … REBUILD`, columnstore, filtrované a zakázané indexy, ani keď je computed / `rowversion` stĺpec v kľúči alebo computed / LOB stĺpec v `INCLUDE`.
- Od SQL Server 2019 vieš na úrovni databázy vynútiť online / resumable aj pre príkazy, ktoré to nežiadajú (napr. ručný rebuild vývojára): `ALTER DATABASE SCOPED CONFIGURATION SET ELEVATE_ONLINE = WHEN_SUPPORTED;` (obdobne `ELEVATE_RESUMABLE`).

## Veľké tabuľky: po partíciách

- Partíciovaný index môžeš udržiavať **po partíciách** – typicky stačí posledná „živá“ partícia, staré sa nemenia: `ALTER INDEX PK_Orders ON dbo.Orders REBUILD PARTITION = 37 WITH (ONLINE = ON);`
- Rebuild partíciovaného indexu prepočíta štatistiku len **vzorkou** (nie FULLSCAN). Ak ti záleží na presných štatistikách, plánuj ich update zvlášť (pri veľkých partíciovaných tabuľkách zváž inkrementálne štatistiky).

## Columnstore a heap

- **Columnstore:** od SQL Server 2016 je bežnou údržbou `REORGANIZE` – skomprimuje uzavreté delta rowgroups, zlúči malé rowgroups a fyzicky odstráni riadky, keď je v rowgroup zmazaných 10 % a viac. `ALTER INDEX CCI_Sales ON dbo.Sales REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);` Rebuild clustered columnstore je do SQL Server 2017 offline, online od 2019 (Enterprise).
- **Heap** sa reorganizovať nedá. `ALTER TABLE dbo.MojaTabulka REBUILD;` odstráni forwarded records, ale **prebuduje aj všetky nonclustered indexy** tabuľky (menia sa RID). Na veľkej tabuľke radšej clustered index.

## Ako sledovať priebeh

- **REORGANIZE** hlási `percent_complete` v `sys.dm_exec_requests` (napr. recept [Priebeh BACKUP / RESTORE / DBCC](script.php?id=21&s=priebeh-backup-restore-dbcc)).
- **Resumable REBUILD** – `sys.index_resumable_operations` vyššie.
- **Bežný REBUILD** percento nehlási. Vidíš aspoň, či beží, na čo čaká a koho blokuje:

```sql
SELECT r.session_id, r.command, r.start_time, r.status, r.wait_type, r.wait_time, r.blocking_session_id,
       r.percent_complete, r.cpu_time, r.reads, r.writes, r.logical_reads, t.text AS sql_text
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE t.text LIKE N'%ALTER INDEX%'
  AND r.session_id <> @@SPID;
```

Údržba spustená jobom: [SQL Agent – práve bežiace joby](script.php?id=41&s=sql-agent-prave-beziace-joby).

## IndexOptimize (Ola Hallengren) – rozumné nastavenie

Väčšina serverov robí údržbu cez `IndexOptimize` z [SQL Server Maintenance Solution](https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html) (Ola Hallengren, MIT). Predvolené nastavenie: fragmentácia 5–30 % → reorganize (alebo rebuild), nad 30 % → **rebuild online, a ak online nejde, offline**, indexy od 1000 stránok, štatistiky sa neriešia.

> [!WARNING]
> Na **Standard** edícii online rebuild nejde, takže predvolené `@FragmentationHigh` znamená **offline rebuild** – zámok na tabuľke počas celého rebuildu. Ak to nechceš, vyhoď z akcií `INDEX_REBUILD_OFFLINE`.

Príklad (nie pravidlo – prahy a časy uprav podľa merania):

```sql
-- Denne: štatistiky, len tie so zmenami
EXECUTE dbo.IndexOptimize
    @Databases = 'USER_DATABASES',
    @FragmentationLow = NULL, @FragmentationMedium = NULL, @FragmentationHigh = NULL,
    @UpdateStatistics = 'ALL',
    @OnlyModifiedStatistics = 'Y',
    @LogToTable = 'Y';

-- Týždenne: indexy s vyššími prahmi, nikdy offline rebuild, časový limit
EXECUTE dbo.IndexOptimize
    @Databases = 'USER_DATABASES',
    @FragmentationLow = NULL,
    @FragmentationMedium = 'INDEX_REORGANIZE',
    @FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REORGANIZE',   -- Standard: reorganize
    @FragmentationLevel1 = 30,
    @FragmentationLevel2 = 50,
    @MinNumberOfPages = 1000,
    @WaitAtLowPriorityMaxDuration = 5,
    @WaitAtLowPriorityAbortAfterWait = 'SELF',
    @TimeLimit = 14400,          -- po 4 hodinách nespustí ďalší príkaz
    @LogToTable = 'Y';
```

- `@TimeLimit` (v sekundách) **nezastaví bežiaci príkaz** – len po limite nespustí ďalší. Jeden obrovský rebuild ho prekročí o hodiny; na také použi `@Resumable = 'Y'` alebo partície.
- `@LogToTable = 'Y'` zapisuje do `dbo.CommandLog` – vidíš, ktoré indexy sa udržiavajú každý týždeň znova (kandidáti na iný fill factor alebo na to, aby si ich prestal riešiť) a koľko to trvá.
- Kód berieme vždy z originálu na ola.hallengren.com.

## Na čo si dať pozor

- **Nezmenšuj súbor po rebuilde.** `DBCC SHRINKFILE` presúva stránky z konca súboru na začiatok a index znova fragmentuje. Voľné miesto po rebuilde nechaj – ďalší rebuild ho bude potrebovať.
- **KILL dlhého rebuildu** (okrem resumable) spustí rollback, ktorý môže trvať rovnako dlho ako rebuild doteraz. Reorganize môžeš zastaviť kedykoľvek – hotová práca ostane.
- **REBUILD zapne zakázaný index** – aj pri `ALTER INDEX ALL`. Ak niekto index zámerne vypol, po údržbe je späť (a udržiava sa pri každom zápise).
- **Rebuild clustered indexu neprebuduje nonclustered** indexy (iba s `ALL`). Vytvorenie alebo zrušenie clustered indexu ich naopak prebuduje všetky.
- **Fill factor** neznižuj plošne (napr. na celom serveri na 80). Microsoft neodporúča iné hodnoty ako 0 / 100 okrem indexov s veľkým počtom page splitov – nižší fill factor = viac stránok pre všetky čítania.
- **Indexy na GUID / náhodnom kľúči** sa fragmentujú hneď po rebuilde znova. Každotýždenný rebuild ich „neopraví“ – rozhodni sa vedome (fill factor, iný kľúč, alebo ich nechaj tak).
- `ALLOW_PAGE_LOCKS = OFF` → reorganize zlyhá. Offline alebo read-only filegroup → `ALTER INDEX ALL` zlyhá celý.
- `ALTER INDEX … REBUILD` v **explicitnej transakcii** drží log aj zámky až do `COMMIT`.
- Po rebuilde sa prepočítajú štatistiky indexu, takže sa dotazy nad tabuľkou prekompilujú – po údržbe skontroluj [Query Store – regresie](script.php?id=26&s=query-store-regresie-24-h-vs-predoslych-24-h).
- Ak job so štatistikami beží **po** rebuilde a nepoužíva len zmenené štatistiky, prepíše čerstvú FULLSCAN štatistiku vzorkou. `@OnlyModifiedStatistics = 'Y'` to rieši (štatistika po rebuilde nemá zmeny).

## Postup pre veľkú databázu

1. **Inventár:** edícia (online áno / nie), recovery model, AG / log shipping, veľkosť najväčších indexov (dotaz vyššie), voľné miesto vo filegroups, na LOG disku a v tempdb.
2. **Zmeraj**, či je problém: hustota a fragmentácia najväčších a najpoužívanejších indexov (SAMPLED po tabuľkách), porovnaj s výkonom dotazov v Query Store.
3. **Štatistiky** obnovuj častejšie (denne, len zmenené) – lacné a väčšinou s najväčším efektom.
4. **Indexy** udržiavaj zriedkavejšie, s vyššími prahmi, prednostne reorganize; rebuild online a resumable, veľké tabuľky po partíciách, s `@TimeLimit` a v čase mimo záloh a CHECKDB.
5. **Počas údržby** častejšie log backupy, sleduj log, AG queues a blokovanie.
6. **Po údržbe** over: veľkosť logu a DIFF zálohy, AG je `SYNCHRONIZED`, žiadne regresie v Query Store. Výsledky z `CommandLog` porovnaj s ďalším týždňom.

> [!TIP]
> Dobrá otázka pri každom indexe, ktorý sa udržiava každý týždeň: „Zrýchlilo sa po údržbe niečo, čo vieme zmerať?“ Ak nie, údržba len generuje log, zálohy a riziko.

## Zdroje

- [Optimize index maintenance to improve query performance and reduce resource consumption (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes)
- [ALTER INDEX (Transact-SQL) (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-index-transact-sql)
- [How online index operations work (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/how-online-index-operations-work)
- [Disk space requirements for index DDL operations (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/disk-space-requirements-for-index-ddl-operations)
- [Transaction log disk space for index operations (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/transaction-log-disk-space-for-index-operations)
- [sys.index_resumable_operations (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-index-resumable-operations)
- [Editions and supported features of SQL Server 2025 (Microsoft Learn)](https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025)
- [SQL Server Index and Statistics Maintenance – IndexOptimize (Ola Hallengren)](https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html)

_T-SQL v návode je staticky overený proti dokumentácii Microsoft Learn (overené 8. 11. 2026), nie spustený na živom serveri. Pred použitím na PROD ho vyskúšaj na TEST._