Indici e statistiche: la manutenzione che sposta i piani

La frammentazione di un indice si affronta in due modi. Il reorganize è sempre online, riordina il livello foglia, è interrompibile senza perdere il lavoro fatto e consuma poco log: è la scelta per frammentazione moderata e finestre di manutenzione strette. Il rebuild ricrea l’indice ed elimina del tutto la frammentazione, ma richiede spazio aggiuntivo, genera molto più log e, senza l’opzione ONLINE, blocca il carico. La linea guida classica ragiona per soglie: sotto il 5% non si interviene, fra 5% e 30% si preferisce il reorganize, oltre il 30% il rebuild. Sono indicazioni, non regole: su tabelle piccole la manutenzione non produce benefici misurabili.

Le statistiche pesano più degli indici, perché è da lì che il query optimizer stima le righe. Statistiche stantie producono stime sbagliate e quindi memory grant sottodimensionati, join fisici inadatti, piani seriali dove servirebbe parallelismo. L’aggiornamento automatico (AUTO_UPDATE_STATISTICS, eventualmente in modalità asincrona per non far attendere la compilazione) copre il caso ordinario, ma scatta solo dopo un volume di modifiche significativo: dopo un caricamento massivo, o su colonne con distribuzione fortemente asimmetrica, serve un aggiornamento pianificato con campionamento più alto o FULLSCAN sulle statistiche critiche. Il trade-off è sempre lo stesso: più campionamento, stime migliori, durata e costo maggiori.

Integrità: DBCC CHECKDB vale anche nel PaaS

DBCC CHECKDB verifica la coerenza fisica e logica del database: allocazione, pagine, corrispondenza fra indici e dati di base, metadati. L’opzione PHYSICAL_ONLY riduce durata e impatto e si presta a esecuzioni frequenti sui database grandi, con il controllo completo a cadenza più ampia. Nei servizi gestiti la piattaforma sorveglia l’integrità dello storage, ma la verifica resta buona pratica, soprattutto dopo restore o migrazioni. Cambia il rimedio: su SQL Server e su VM esistono le opzioni di riparazione, che richiedono accesso esclusivo e possono comportare perdita di dati; su Azure SQL Database la strada corretta è il point-in-time restore dai backup automatici.

Automatic tuning, IQP e leve di configurazione

L’automatic tuning si appoggia interamente al Query Store: senza Query Store attivo e in stato read-write non c’è storia dei piani, quindi non c’è tuning automatico. Le opzioni sono il forzamento dell’ultimo piano buono (FORCE_LAST_GOOD_PLAN), che rimedia alle regressioni di piano, e la creazione e rimozione automatica degli indici, disponibile su Azure SQL Database; su Managed Instance e su SQL Server il perimetro si limita alla correzione automatica dei piani. Il sistema verifica l’effetto e torna indietro se le prestazioni peggiorano.

La database-scoped configuration porta a livello di singolo database impostazioni che altrove sarebbero d’istanza: MAXDOP, LEGACY_CARDINALITY_ESTIMATION, PARAMETER_SNIFFING, QUERY_OPTIMIZER_HOTFIXES. È la leva giusta quando un solo database ha bisogno di un comportamento diverso, ed è l’unica disponibile dove l’istanza non si tocca.

L’intelligent query processing migliora l’esecuzione senza riscrivere le query: adaptive join, memory grant feedback, interleaved execution, table variable deferred compilation, scalar UDF inlining. Molte di queste funzionalità dipendono dal compatibility level, quindi innalzarlo — dopo aver misurato con Query Store — è spesso l’intervento a maggior rendimento e a costo nullo.

Il Resource Governor isola i carichi con resource pool, workload group e funzione di classificazione, limitando CPU, memoria e IO di un carico rispetto a un altro. Esiste su SQL Server e su Azure SQL Managed Instance, non su Azure SQL Database, dove l’isolamento si ottiene separando i database, usando un elastic pool o indirizzando la reportistica su una replica leggibile. Lo scaling di calcolo e archiviazione è l’ultima leva, non la prima: alza il costo in modo permanente e maschera un piano sbagliato invece di correggerlo.

Trappole tipiche d’esame

  • Query improvvisamente lenta dopo un caricamento massivo → aggiornare le statistiche: la distribuzione è cambiata e le stime sono fuori scala; ricostruire gli indici o scalare il service tier non tocca la causa.
  • Rebuild appena eseguito, poi UPDATE STATISTICS con campionamento predefinito → si peggiora: il rebuild aggiorna le statistiche dell’indice a scansione completa, un aggiornamento campionato successivo le degrada.
  • Manutenzione senza fermare il carico, frammentazione moderata → reorganize: è online e interrompibile; il rebuild offline è la risposta sbagliata quando il vincolo è la disponibilità.
  • Isolare un carico di reporting da quello transazionale su Azure SQL Database → non Resource Governor: lì non esiste; si separa il database, si usa un elastic pool o una secondaria leggibile.
  • Regressione di piano dopo un aggiornamento → FORCE_LAST_GOOD_PLAN: presuppone Query Store attivo; se lo scenario dice che è disattivato, il primo passo è abilitarlo.
  • MAXDOP diverso per un solo database di un’istanza condivisa → database-scoped configuration: l’impostazione a livello di istanza colpirebbe tutti i database.