...

Istogrammi MySQL – Piani di query ottimizzati senza indici

Istogrammi MySQL forniscono all’ottimizzatore dati di distribuzione reali, consentendogli di stimare correttamente le selettività e di generare piani di query più veloci – spesso persino senza indici aggiuntivi. Vi mostrerò come impostare e controllare gli istogrammi in MySQL 8+ con ANALYZE TABLE e come utilizzarli per prendere decisioni migliori in caso di join, filtri e scansioni.

Punti centrali

In breve: I seguenti punti chiave illustrano gli aspetti a cui presto particolare attenzione quando utilizzo gli istogrammi.

  • Selettività Invece di affidarsi all’istinto: stime di cardinalità più realistiche
  • Senza indice più veloce: scelta migliore del piano in caso di distribuzioni asimmetriche
  • Tipi Comprendere: l'uso mirato di Singleton e Equi-Height
  • Secchielli gestire: valutare la soppressione rispetto ai costi dei metadati
  • Cura In primo piano: aggiornare, verificare, eliminare se necessario

Perché gli istogrammi senza indice sono efficaci

Uso Istogrammi, perché altrimenti l’ottimizzatore spesso ipotizza una distribuzione uniforme e di conseguenza sceglie piani non ottimali. Un istogramma rappresenta la Distribuzione dei valori partendo da un intervallo approssimativo di una colonna e fornendo così stime realistiche della selettività per predicati come =, >, BETWEEN, IN o IS NULL. L’ottimizzatore decide quindi se sia più vantaggiosa una scansione di intervallo dell’indice, una scansione della tabella o una strategia di join con Nested Loops. Se, ad esempio, una condizione interessa solo lo 0,1% delle righe, preferisco un accesso mirato piuttosto che una scansione estesa. Se invece un filtro copre quasi tutte le righe, rinuncio a costosi accessi agli indici che non apportano alcun vantaggio, aumentando così la Efficienza di ogni piano.

Tipi di istogramma in MySQL 8.0

Distinguo due Tipi: Singleton ed Equi-Height. Gli istogrammi Singleton raggruppano i valori singoli più frequenti in intervalli separati – ideali per colonne con poche categorie dominanti come „attivo“, „inattivo“ o „archiviato“. Gli istogrammi Equi-Height suddividono l’intervallo di valori in modo tale che ogni intervallo contenga un numero simile di Linee ; questa opzione è adatta a distribuzioni continue o distorte, come prezzi, timestamp o intervalli di ID „con lacune“. Entrambe le varianti forniscono all’ottimizzatore percentuali di corrispondenza più precise per i filtri. Scelgo sempre il tipo in base alle caratteristiche dei dati, non in base alle mie preferenze personali.

Nozioni tecniche di base: gestire la scelta del tipo di dati in MySQL

MySQL determina la specifica Variante dell'istogramma automaticamente in base alla distribuzione dei dati. In pratica, ciò significa che se il numero di valori distinti (NDV) è sufficientemente basso rispetto al numero di intervalli, si ottiene di fatto un istogramma singleton; in caso contrario, viene generato un istogramma equi-height. Pertanto, „scelgo“ il tipo indiretto, specificando la colonna appropriata e un numero adeguato di bucket. Per le colonne con pochissime categorie, ma fortemente dominanti, imposto volutamente pochi bucket per ottenere una precisione simile a quella dei singleton per questi valori. In caso di dati continui e finemente distribuiti, aumento gradualmente il numero di bucket fino a quando EXPLAIN non restituisce il risultato desiderato. Selettività riflette.

Importante: gli istogrammi sono a colonna singola. Non è possibile rappresentare direttamente le dipendenze tra colonne (ad esempio, "status" e "country"). In questi casi, è utile applicare un istogramma alla colonna più selettiva e impostare di conseguenza l'ordine dei join.

Scegliere i secchi in modo corretto

MySQL utilizza 100 per impostazione predefinita Secchielli, ma consente di impostare valori compresi tra 1 e 1024 tramite WITH N BUCKETS. Un numero maggiore di bucket aumenta la risoluzione, ma comporta un aumento dei metadati e del carico di analisi. Di solito parto con un valore prudente, valuto l’effetto su EXPLAIN e lo aumento gradualmente se il piano continua a sembrare inadeguato. In presenza di valori fortemente concentrati (ad es. 90 % in uno stato) spesso bastano pochi bucket; in caso di prezzi o timestamp distribuiti in modo più uniforme, conviene utilizzare più bucket. L’obiettivo è un’impostazione ragionevole Granularità, riducendo sensibilmente gli errori di valutazione senza aumentare inutilmente l'onere amministrativo.

Esempio pratico: flusso di lavoro con ANALYZE TABLE

Seguo una linea chiara Flusso di lavoro: Per prima cosa identifico le colonne che compaiono spesso nelle condizioni WHERE o JOIN e che presentano distribuzioni palesemente asimmetriche. Quindi genero un istogramma con ANALYZE TABLE tbl UPDATE HISTOGRAM ON col WITH N BUCKETS; e lo verifico tramite INFORMATION_SCHEMA.COLUMN_STATISTICS. Dopo eventuali spostamenti dei dati, aggiorno nuovamente con ANALYZE TABLE. Se una statistica non è corretta, la rimuovo con ANALYZE TABLE tbl DROP HISTOGRAM ON col;. Per valutare l’efficacia del piano di esecuzione, leggo Interpretazione di EXPLAIN ANALYZE e le stesse stime rispetto ai dati effettivi Linee da.

Ordini concreti e controllo

Lavoro in modo riproducibile seguendo pochi passaggi chiari e verifico le statistiche JSON generate.

-- Creare istogrammi su singole colonne
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 32 BUCKETS;
ANALYZE TABLE orders UPDATE HISTOGRAM ON created_at WITH 128 BUCKETS;

-- Più colonne in un unico ciclo con lo stesso numero di bucket
ANALYZE TABLE orders UPDATE HISTOGRAM ON status, payment_method WITH 64 BUCKETS;

-- Eliminare in modo mirato gli istogrammi
ANALYZE TABLE orders DROP HISTOGRAM ON status;
-- Controllo visivo delle statistiche
SELECT
  SCHEMA_NAME, TABLE_NAME, COLUMN_NAME,
  JSON_PRETTY(HISTOGRAM) AS histogram
FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
WHERE SCHEMA_NAME = DATABASE()
  AND TABLE_NAME = 'orders'
  AND COLUMN_NAME IN ('status','created_at');

Valuto l'effetto immediatamente con EXPLAIN ANALYZE:

EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE status = 'canceled'
  AND created_at >= NOW() - INTERVAL 7 DAY;

La stima migliora righe Se si nota un cambiamento significativo e il piano passa, ad esempio, da una scansione completa (Full Scan) a una scansione per intervallo di indice (Index-Range-Scan) oppure modifica l'ordine dei join, la misura ha avuto successo. Se la differenza rimane significativa, aumento o riduco il numero di bucket e ricontrollo.

Esempio: stato degli ordini e valori rari

In una tabella degli ordini, lo stato „completed“ è spesso quello predominante, mentre „pending“ è abbastanza frequente e „canceled“ è molto raro; questo squilibrio senza un istogramma porta facilmente a selettività errate. Se un’API esegue una query su „canceled“, l’ottimizzatore potrebbe erroneamente scegliere una scansione completa della tabella, anche se sarebbe sufficiente un accesso mirato tramite indice. Con un istogramma singleton, MySQL riconosce che „canceled“ rappresenta solo una piccolissima percentuale e passa a una scansione dell’intervallo dell’indice oppure ottimizza l’ordine dei join. In questo modo si riduce la latenza e non ho bisogno di un indice aggiuntivo per ogni Variante di un filtro. Nei dashboard con SLO rigidi, questa correzione comporta spesso notevoli vantaggi in termini di reattività.

Serie temporali e timestamp

Nel caso delle serie temporali, ci sono molti Accessi sulla base di dati recenti; le fasce temporali più vecchie rimangono per lo più inattive. Un istogramma Equi-Height su created_at o updated_at distingue gli intervalli di tempo molto frequentati da quelli utilizzati raramente. L’ottimizzatore valuta quindi correttamente se sia opportuno eseguire una scansione per intervallo (Range Scan) o se una scansione della tabella (Table Scan) consenta di raggiungere l’obiettivo più rapidamente. Soprattutto in caso di filtri temporali parziali su tabelle di grandi dimensioni, riscontro evidenti cambiamenti nel piano di esecuzione e minori costi di I/O. Ritengo che la Statistiche qui viene aggiornato più spesso, perché l'attenzione si sposta sulle attività quotidiane.

Partizioni, tipi di dati e collazioni

Sulle tabelle partizionate, esamino la distribuzione dei dati su tutte le partizioni. Forti variazioni (ad esempio su base mensile) possono appiattire gli istogrammi globali. Se singole partizioni sono estremamente selettive o estremamente ampie, verifico inoltre, utilizzando filtri di “partition pruning” nella clausola WHERE, se la qualità del piano di esecuzione sia comunque adeguata. In generale, mi assicuro di formulare i filtri in modo che MySQL possa individuare le partizioni in una fase precoce escludere può.

Gli istogrammi funzionano al meglio con tipi di dati scalari e comparabili (numeri, valori di data/ora, VARCHAR/CHAR con collazione adeguata). Nel caso di Dati LOB/JSON preferisco puntare su Colonne generate con valori estratti e tipizzati e, se necessario, li correda di istogrammi o indici. Nel caso delle stringhe, la Raccolta la logica di confronto; a seconda della collazione, i valori possono coincidere (ad es. maiuscole/minuscole). Mantengo la collazione coerente con le query per ottenere selettività realistiche.

Limiti ed errori

Gli istogrammi rappresentano principalmente singole colonne con Costanti Bene; tuttavia, rappresentano le dipendenze tra più colonne solo in misura limitata. In presenza di colonne fortemente correlate o di parametri dinamici (ad esempio, compilati dall’applicazione) raggiungono i propri limiti. I campi booleani o le colonne con una distribuzione pressoché uniforme raramente traggono vantaggio da ulteriori analisi statistiche. Troppi intervalli e una manutenzione eccessiva possono a loro volta aumentare i tempi di gestione e analisi. Per questo motivo utilizzo gli istogrammi in modo mirato e verifico regolarmente i Effetto su modelli reali.

Controllo e aggiornamento dell'Optimizer

Controllo il Utilizzo dagli istogrammi, passando per ANALYZE TABLE e le opzioni dell’ottimizzatore pertinenti, affinché il pianificatore utilizzi le statistiche in modo efficace. Nei sistemi con carico elevato, pianifico l’aggiornamento in fasce orarie di minor traffico o in batch dopo carichi di dati di grandi dimensioni. Prima e dopo confronto i risultati di EXPLAIN e EXPLAIN ANALYZE per valutare le modifiche apportate all’ordine delle join, alle fasi di filtraggio e ai modelli di costo. In caso di effetti negativi, intervengo immediatamente e ripristino una statistica precedente. Per un controllo più approfondito della Opzioni dell'ottimizzatore mi assicuro che le dipendenze con altre statistiche non causino errori inosservati Ipotesi produrre.

Monitoraggio, protezione dalla regressione e playbook

Mi sto costruendo un modello leggero Playbook per l'ambiente di produzione:

  • Definire la linea di base: prima di apportare modifiche, eseguire EXPLAIN ANALYZE, registrare il tempo di esecuzione, il numero di „righe esaminate“ e il contatore dell’handler.
  • Creare/modificare un istogramma: concentrarsi specificatamente sulle colonne dei filtri, con intervalli conservativi.
  • Misurare subito dopo: piano, righe stimate rispetto a quelle effettive; un fattore di scostamento >10 è per me un segnale di allarme.
  • Regolazione di precisione: alzare/abbassare i bucket; se necessario, modificare l'ordine dei filtri nella query.
  • Tenere pronto un rollback: DROP HISTOGRAM, nel caso in cui aumentino le latenze.
  • Automazione: eseguire ANALYZE durante le finestre di manutenzione, dopo i caricamenti ETL o dopo ondate significative di operazioni DML.

Per analizzare le cause utilizzo Tracce dell'ottimizzatore e EXPLAIN ANALYZE, per verificare se il pianificatore, sulla base degli istogrammi, metta in primo piano la tabella selettiva corretta. Per i test A/B, a titolo sperimentale, fisso l’ordine dei join (STRAIGHT_JOIN) oppure impongo o disabilito singoli indici, al fine di valutare in modo isolato l’effetto delle statistiche.

Dal punto di vista organizzativo, si rivela utile un breve Registro delle modifiche Per ogni tabella: colonna, numero di bucket, momento, valori misurati prima/dopo. Ciò facilita le successive correzioni ed evita interazioni poco chiare.

Aspetti operativi: blocchi, costi, portabilità

ANALYZE TABLE accetta una Blocco dei metadati sulla tabella, ma non blocca in modo permanente le normali operazioni di lettura/scrittura. Per tabelle molto grandi, prevedo un tempo sufficiente; la generazione dell’istogramma funziona con campioni ed è limitata dalla memoria (parola chiave: memoria di lavoro interna per il calcolo). Lo spazio richiesto dalle statistiche stesse rimane moderato: da qualche dozzina a poche centinaia di kilobyte per colonna con 100–256 bucket è un valore di riferimento realistico. In totale, però, faccio comunque i conti, perché molte colonne moltiplicate per molte tabelle danno come risultato metadati visibili.

All'indirizzo Dump logici (mysqldump) gli istogrammi non vengono trasferiti insieme ai dati; dopo un ripristino, li ricreo in modo mirato. In caso di aggiornamento in-place, invece, vengono mantenuti. Dal punto di vista dei diritti, ho bisogno di privilegi sufficienti per eseguire ANALYZE TABLE sugli oggetti interessati; in ambienti rigorosamente regolamentati, integro questa attività nelle pipeline di manutenzione.

Quando gli istogrammi non servono a nulla

Mi risparmio Istogrammi su colonne che contengono pochissimi valori e che possono comunque essere valutate con precisione. Anche nei casi in cui un buon indice copra già insiemi minimi di risultati, un istogramma raramente offre un vantaggio aggiuntivo. Le distribuzioni uniformi non richiedono una granularità complessa. Nei sistemi altamente dinamici e con un'elevata attività di scrittura, la manutenzione può generare un carico superfluo se la avvio troppo frequentemente. In tali situazioni, impiego la Energia piuttosto nelle strategie di indicizzazione, nella progettazione delle query e nel caching.

Scheda riassuntiva in forma di tabella

Utilizzo il seguente Panoramica Per prendere decisioni rapide: quale tipo di istogramma è più adatto, come impostare i bucket e quali sono i costi associati. La tabella funge da promemoria durante le revisioni delle query problematiche. La aggiorno sulla base delle conoscenze acquisite tramite EXPLAIN ANALYZE e delle metriche di produzione. Nel farlo, tengo conto del fatto che le distribuzioni dei dati cambiano e che le ipotesi storiche diventano obsolete. Rimane fondamentale che la Qualità del progetto con misurazioni reali.

Aspetto Raccomandazione Benefici compromesso Esempio
Tipo Singleton in presenza di pochi valori dominanti Percentuali di corrispondenza esatte per le categorie più comuni Poco utile in caso di aree continue stato_ordine
Tipo Equi-Height in presenza di dati distorti e continui Stima più accurata lungo l'intervallo di valori Maggiori metadati in presenza di numerosi bucket created_at, price
Secchielli Inizia da 100, poi regola di conseguenza Risoluzione bilanciata Maggiore carico di analisi e di memoria con 512–1024 CON 100 SECCHI
Cura Dopo modifiche significative ai dati, eseguire ANALYZE Selettività attuali Pianificare le finestre di manutenzione ANALYZE TABLE … UPDATE HISTOGRAM
Controllo Verifica tramite COLUMN_STATISTICS Trasparenza e revisione contabile È necessaria l'interpretazione JSON INFORMATION_SCHEMA.COLUMN_STATISTICS

Inserimento nel quadro generale del tuning

Io tratto Istogrammi come elemento fondamentale insieme agli indici, alla progettazione delle query, alla cache e ai parametri hardware. Spesso un buon istogramma modifica l’ordine dei join, riduce l’I/O e garantisce tempi di risposta costanti. Tuttavia, non sostituisce né strategie di indicizzazione ben strutturate né uno schema efficiente. Chi analizza più a fondo le decisioni relative alla pianificazione, trae vantaggio da Comprendere i piani di esecuzione e mette a confronto i modelli di costo con i tempi effettivi. Verifico regolarmente se il Carichi di lavoro se siano ancora in linea con le statistiche o se siano necessari degli adeguamenti.

Scenari avanzati di join

Gli istogrammi risultano particolarmente utili quando sono coinvolte più tabelle con filtri. Esempio:

SELECT o.id, o.amount
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.country = 'DE'
  AND o.status = 'canceled'
  AND o.created_at >= NOW() - INTERVAL 30 DAY;

Senza istogrammi, l’ottimizzatore potrebbe sottovalutare la selettività di o.status=’canceled‘ o sovrastimare la percentuale di utenti tedeschi. Con un istogramma su e.paese e o.status (eventualmente anche su o.created_at) il progettista si rende solitamente conto che la combinazione è estremamente selettiva. In pratica, osservo che MySQL determina prima il sottoinsieme più piccolo (ad esempio tramite indice su users(country) o orders(status, created_at)) e solo successivamente esegue il join, invece di eseguire la scansione della tabella più grande. Ciò consente di risparmiare I/O, buffer e CPU e stabilizza la latenza anche sotto carico.

Poiché gli istogrammi sono solo a colonna singola le strategie basate sugli indici rimangono importanti: un indice composto su (status, created_at) può accelerare ulteriormente la scansione dell'intervallo. L'istogramma garantisce in questo caso soprattutto che l'ottimizzatore Strategia ritiene addirittura conveniente.

Sintesi per la pratica

Ho impostato MySQL-Utilizzo gli istogrammi quando l’ottimizzatore sbaglia i calcoli con le statistiche predefinite e le distribuzioni asimmetriche generano piani errati. Con ANALYZE TABLE creo, aggiorno e rimuovo in modo mirato le statistiche sulle colonne che predominano nei filtri e nei join. Scelgo tra Singleton ed Equi-Height in base ai dati, mentre calibro il numero di bucket tramite misurazioni. Con EXPLAIN ANALYZE verifico se l’ordine dei join, le posizioni dei filtri e le scansioni cambiano come desiderato. In questo modo ottengo con poco Spese generali query notevolmente più veloci – spesso senza bisogno di ulteriori indici.

Articoli attuali

Centro dati con rack di server e visualizzazione stilizzata dei dati per l’ottimizzazione delle prestazioni di MySQL
Banche dati

Istogrammi MySQL – Piani di query ottimizzati senza indici

Scopri come gli istogrammi di MySQL forniscono all’ottimizzatore statistiche precise, consentono di ottenere piani di query migliori e migliorano notevolmente l’ottimizzazione SQL senza bisogno di indici aggiuntivi.