Risposte:
La risposta, come al solito (va bene, la maggior parte delle volte), sta nel piano di esecuzione.
Esistono alcuni operatori che richiedono che tutte le righe arrivino prima di poter iniziare a elaborarle e passarle a valle, ad esempio:
Vengono chiamati operatori di blocco o stop and go per questo motivo e vengono spesso scelti quando l'ottimizzatore pensa che dovrà elaborare un sacco di dati per trovare i tuoi dati.
Esistono altri operatori in grado di avviare lo streaming o passare immediatamente qualsiasi riga trovata
Quando le query iniziano a restituire immediatamente i dati, ma non finiscono immediatamente, di solito è un segno che l'ottimizzatore ha scelto un piano per individuare e restituire rapidamente alcune righe utilizzando operatori con un costo di avvio inferiore.
Ciò può accadere a causa degli obiettivi di riga introdotti da te o dall'ottimizzatore.
Può anche accadere se per qualche motivo viene scelto un piano errato (mancanza di SARGability, sniffing dei parametri, statistiche insufficienti, ecc.), Ma ciò richiede più scavi per capire.
Per ulteriori informazioni, consulta il blog di Rob Farley qui
E la serie di Paul White sui goal di fila qui , qui , qui e qui .
Va anche notato che, se si parla di SSMS, le righe vengono visualizzate solo dopo aver riempito un intero buffer, non solo volenti o nolenti.
Se capisco cosa stai osservando, questo è il modo in cui Management Studio esegue il rendering delle righe e ha poco a che fare con il modo in cui SQL Server restituisce le righe. Infatti, spesso quando si restituiscono grandi risultati a SSMS e si tenta di renderli in una griglia, SSMS non riesce a tenere il passo e SQL Server finisce per attendere che l'app elabori più righe. In questo caso vedrai che SQL Server accumula le ASYNC_NETWORK_IO
attese.
Puoi controllarlo in qualche modo usando Risultati su testo anziché Risultati su griglia, poiché SSMS può disegnare il testo più velocemente di quanto possa disegnare griglie, ma probabilmente scoprirai che ciò può influire sulla leggibilità a seconda del numero di colonne e dei tipi di dati coinvolti. Entrambi sono influenzati da quando SSMS decide di scrivere effettivamente i risultati in quel riquadro, che dipende da quanto è pieno il buffer di output.
Quando si hanno più istruzioni e si desidera forzare il buffer a eseguire il rendering dei risultati di output nel riquadro dei messaggi, è possibile utilizzare un piccolo trucco di stampa tra le istruzioni:
RAISERROR('', 0, 1) WITH NOWAIT;
Ma questo non aiuta quando stai cercando di far sì che SSMS esegua il rendering delle righe più rapidamente quando tutto l'output proviene da una singola istruzione.
Più direttamente, puoi controllarlo limitando il numero di risultati che stai visualizzando in SSMS. Vedo spesso le persone lamentarsi del tempo impiegato per restituire un milione di righe alla griglia. Cosa diavolo farà qualcuno con un milione di righe in una griglia SSMS, non ne ho idea.
Ci sono alcuni hack come OPTION (FAST 100)
, che ottimizzeranno per recuperare quelle prime 100 righe (o qualsiasi 100 righe se non c'è esterno ORDER BY
), ma questo può comportare un costo molto più lento di recupero per il resto delle righe e un piano che è più nel complesso inefficiente, quindi non è davvero un'opzione di riferimento IMHO.
La tua domanda non riguarda SQL Server in sé ma:
C'è un modo per controllarlo?
Risposta breve :
sqlcmd
invece di ssms
o sqlcmd
-mode dissms
Risposta lunga :
Ovviamente! Ma non uno - prob
sqlcmd
o in sqlcmd
-mode in ssms.spid
e ottieni l'elenco completo delle impostazioni della sessione. Confronta con le impostazioni della sqlcmd
sessione. Se nulla fa clic: copia tutte le impostazioni della sessione dal profiler nello script di query, esegui in sqlcmd
modalità e cambiando gradualmente le impostazioni troverai il tuo colpevole.In bocca al lupo!
Per aggiungere alla risposta sp_BlitzErik, prendi l'esempio usando a NOT IN ()
con una sottoselezione . Per determinare se un elemento è nel risultato della query nidificata, è (generalmente) necessario recuperare l'intero risultato.
Quindi un modo semplice che ho trovato per migliorare le prestazioni di tali query è quello di riscriverle come una LEFT OUTER JOIN
condizione in cui la condizione per il RIGHT
lato è nulla (puoi capovolgerla, ovviamente, ma chi usa RIGHT OUTER JOINS
?). Ciò consente ai risultati di iniziare a tornare immediatamente.
WHERE t.x IN (<complex SELECT subquery>)
, l'equivalente LEFT JOIN LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL
, quindi anche la sottoquery dovrà essere valutata (quindi lo stesso piano complesso con NOT Nella versione).
NOT EXISTS
ma Oracle NOT IN
nelle query. Ma oggi deve essere considerato un errore nel generatore di piani