Quali fattori di costo vanno nell'ottimizzatore scegliendo diversi tipi di bobine?


15

Spoolum

In SQL Server ci sono diversi tipi di spool. I due che mi interessano sono i rocchetti Table Spool e Index , al di fuori delle query di modifica .

Le query di sola lettura, in particolare sul lato interno di un join Nested Loops, possono utilizzare uno spool Table o Index per ridurre potenzialmente l'I / O e migliorare le prestazioni delle query. Queste bobine possono essere desiderosi o pigri . Proprio come me e te.

Le mie domande sono:

  • Quali fattori vanno nella scelta del rocchetto Table vs. Index
  • Quali fattori vanno nella scelta tra Eager e Lazy Spools

Risposte:


12

Questo è un po 'ampio, ma penso di capire la vera domanda e risponderò di conseguenza. Sto solo per parlare del rocchetto tabella vs indice però. Non credo sia corretto vedere lì come una scelta tra spool di tabella e di indice. Come sapete, è possibile in una singola sottostruttura ottenere uno spool di indice, uno spool della tabella o entrambi uno spool dell'indice e uno spool della tabella. Credo che sia generalmente corretto affermare che si ottiene uno spool di indice nelle seguenti condizioni:

  1. Query Optimizer ha un motivo per trasformare un join in un applicare
  2. Query Optimizer esegue effettivamente la trasformazione per applicare
  3. Query Optimizer utilizza la regola per aggiungere uno spool di indice (almeno lo spool di indice deve essere sicuro da usare)
  4. Il piano con lo spool di indice è selezionato

Puoi vedere la maggior parte di questi con semplici demo. Inizia creando un paio di heap:

DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;


DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Per la prima query, non c'è nulla su cui cercare:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);

Quindi non c'è motivo per cui l'ottimizzatore trasformi il join in un'applicazione. Si finisce con un rocchetto di tabella per motivi di costo. Quindi questa query fallisce il primo test.

inserisci qui la descrizione dell'immagine

Per la query successiva, è lecito aspettarsi che l'ottimizzatore abbia un motivo per considerare un'applicazione:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID 
OPTION (LOOP JOIN, MAXDOP 1);

Ma non è pensato per essere:

inserisci qui la descrizione dell'immagine

Questa query non supera il secondo test. Una spiegazione completa è qui . Citando la parte più rilevante:

L'ottimizzatore non considera la costruzione di un indice al volo per consentire un'applicazione; piuttosto la sequenza di eventi è di solito il contrario: trasformarsi in applicare perché esiste un buon indice.

Posso riscrivere la query per incoraggiare l'ottimizzatore a considerare un'applicazione:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);

Ma non c'è ancora spool di indice:

inserisci qui la descrizione dell'immagine

Questa query non supera il terzo test. In SQL Server 2014 c'era un limite di lunghezza della chiave di indice di 900 byte. Questo è stato esteso in SQL Server 2016 ma solo per indici non cluster. L'indice per uno spool è un indice cluster quindi il limite rimane a 900 byte . In ogni caso, la regola di spooling dell'indice non può essere applicata perché potrebbe causare un errore durante l'esecuzione della query.

Ridurre la lunghezza del tipo di dati a 800 fornisce infine un piano con uno spool di indice:

inserisci qui la descrizione dell'immagine

Il piano di spooling dell'indice, non a caso, è molto più economico di un piano senza spool: 89.7603 unità contro 598.832 unità. Puoi vedere la differenza con il QUERYRULEOFF BuildSpoolsuggerimento per la query non documentata :

inserisci qui la descrizione dell'immagine

Questa non è una risposta completa, ma si spera sia qualcosa di quello che stavi cercando.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.