Stima rispetto al piano di query effettivo con chiamate di funzione


11

Ho questa query su SQL Server, una query di replica di tipo merge:

SELECT DISTINCT
    b.tablenick,
    b.rowguid,
    c.generation,
    sys.fn_MSgeneration_downloadonly
    (
        c.generation,
        c.tablenick
    )
FROM #belong b
LEFT OUTER JOIN dbo.MSmerge_contents c ON 
    c.tablenick = b.tablenick
    AND c.rowguid = b.rowguid;

Il piano di query stimato include informazioni su 3 query:

  1. La query sopra
  2. La funzione chiama a fn_MSgeneration_downloadonly
  3. La chiamata di funzione a fn_MSArticle_has_downloadonly_property

Il piano di query effettivo include solo queste informazioni:

  1. La query sopra

Niente sulle funzioni. Perché le informazioni sulla funzione mancano nel piano attuale?

Ho provato queste opzioni:

SET STATISTICS PROFILE ON
SET STATISTICS XML ON

Il che ha creato un piano reale, ma mancavano le parti 2 e 3 come quando ho usato l'opzione del piano di query effettivo in Management Studio.

Se, ad esempio, dovessi utilizzare Profiler per acquisire le informazioni sulle chiamate di funzione quali eventi selezionerei?


Non ho trovato una risposta specificamente correlata ai piani di query, ma ho profilato SP: StmtStarting e SP: StmtCompleted e ha mostrato le chiamate di funzione.

Risposte:


17

E niente sulle funzioni. Perché le informazioni sulla funzione mancano nel piano attuale?

Questo è di progettazione, per motivi di prestazioni.

Le funzioni che contengono BEGINe ENDnella definizione creano un nuovo frame stack T-SQL per ogni riga di input. Detto in altro modo, il corpo della funzione viene eseguito separatamente per ogni riga di input . Questo singolo fatto spiega la maggior parte dei problemi di prestazioni associati alle funzioni scalare e multiistruzione di T-SQL (si noti che le funzioni con valori di tabella in linea non usano la BEGIN...ENDsintassi).

Nel contesto della tua domanda, ciò comporterebbe un SHOWPLANoutput completo per ogni riga. L'output del piano XML è abbastanza dettagliato e costoso da produrre, quindi produrre un output completo per ogni riga sarebbe una cattiva idea in termini generali.

Esempio

Considera la seguente funzione scalare T-SQL, creata nel database di esempio AdventureWorks , che restituisce il nome di un prodotto dato il suo ID:

CREATE FUNCTION dbo.DumbNameLookup
(
    @ProductID integer
)
RETURNS dbo.Name
AS
BEGIN
    RETURN
    (
        SELECT
            p.Name
        FROM Production.Product AS p
        WHERE
            p.ProductID = @ProductID
    );
END;

Piano di pre-esecuzione

Un piano di pre-esecuzione (piano stimato in SSMS) mostra le informazioni sul piano per l'istruzione parent e le chiamate di funzione nidificate:

-- Pre-execution plan shows main query and nested function call
SET SHOWPLAN_XML ON;
GO
SELECT dbo.DumbNameLookup(1);
GO
SET SHOWPLAN_XML OFF;

Uscita SSMS:

Piano di pre-esecuzione SSMS

Lo stesso XML visualizzato in SQL Sentry Plan Explorer mostra più chiaramente la natura nidificata delle chiamate:

Piano di pre-esecuzione PE

Uscita post-esecuzione

SSMS mostra i dettagli solo per la query principale quando viene richiesto l'output del piano di post-esecuzione:

-- Post-execution plan shows main query only
SET STATISTICS XML ON;
SELECT dbo.DumbNameLookup(1);
SET STATISTICS XML OFF;

Post-esecuzione SSMS

L'impatto sulle prestazioni di fare diversamente può essere mostrato utilizzando la classe di eventi Showplan XML Statistics Profile in SQL Server Profiler, utilizzando una query che chiama la funzione più volte (una volta per riga di input):

SELECT TOP (5)
    p.ProductID,
    dbo.DumbNameLookup(p.ProductID)
FROM Production.Product AS p;

Uscita del profiler:

Traccia output

Esistono cinque piani di post-esecuzione separati per le esecuzioni delle funzioni e uno per la query principale. I cinque piani di funzione si presentano così nel riquadro inferiore del profiler:

Piani funzionali

Il piano di query principale è:

Piano genitore

L'esecuzione della query senza la TOP (5)clausola comporta un piano di esecuzione completo per ciascuna delle 504 righe nella tabella Prodotto. Probabilmente puoi vedere come ciò sfuggirebbe rapidamente ai tavoli più grandi.

La situazione per i trigger è invertita. Questi non mostrano alcuna informazione sul piano di pre-esecuzione, ma includono un piano di post-esecuzione. Ciò riflette la natura basata su set di trigger; ognuno viene attivato una volta per tutte le righe interessate, anziché una volta per riga.


@PaulWhite c'è qualche buona ragione per cui i piani trigger non vengono mostrati quando si richiede il piano di esecuzione stimato? Sembra un'utile caratteristica mancante. Potrei creare un elemento di connessione per questo.
usr

@usr - Forse perché l'attuale piano memorizzato nella cache selezionato può variare in base al numero effettivo di righe come descritto qui? technet.microsoft.com/en-us/library/…
Martin Smith,

@MartinSmith potrebbe essere un motivo. Recentemente un elemento connect per i piani di esecuzione dei vincoli check e fk è stato contrassegnato come completato, quindi speravo che avrebbero fatto la stessa cosa con i trigger.
usr

@usr - Questo qui ? 3 mesi? Questo deve essere un record per una nuova richiesta di funzionalità!
Martin Smith,

@MartinSmith sì, quello. È stato "riparato" un 1-2 fa. Spero davvero di non dover interrogare l'archivio query. Speravo di fare clic su un pulsante in SSMS. In realtà, sono stato sorpreso di vedere alcun cambiamento a una parte del motore che non è stata toccata negli anni. Ma forse non c'era nessuno.
usr
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.