C'è qualche vantaggio in SCHEMABINDING una funzione oltre la protezione di Halloween?


52

È noto che SCHEMABINDINGuna funzione può evitare uno spooling non necessario nei piani di aggiornamento:

Se si utilizzano UDF T-SQL semplici che non toccano alcuna tabella (ovvero non accedono ai dati), assicurarsi di specificare l' SCHEMABINDINGopzione durante la creazione degli UDF. Ciò renderà gli UDF associati allo schema e garantirà che Query Optimizer non generi operatori di spool non necessari per i piani di query che coinvolgono questi UDF.

Ci sono altri vantaggi di SCHEMABINDINGuna funzione, anche se non accede ai dati?

Risposte:


78

Sì.

Se non si specifica WITH SCHEMABINDING, SQL Server ignora i controlli dettagliati che esegue normalmente sul corpo della funzione. Contrassegna semplicemente la funzione come accesso ai dati (come indicato nel collegamento indicato nella domanda).

Questa è un'ottimizzazione delle prestazioni. In caso contrario, SQL Server dovrebbe eseguire i controlli dettagliati su ogni chiamata di funzione (poiché la funzione non associata potrebbe cambiare in qualsiasi momento).

Esistono cinque importanti proprietà delle funzioni:

  • Determinismo
  • Precisione
  • Accesso ai dati
  • Accesso ai dati di sistema
  • Verifica del sistema

Ad esempio, prendi la seguente funzione scalare non associata:

CREATE FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
AS
BEGIN
    RETURN '19000101';
END;

Possiamo esaminare le cinque proprietà usando una funzione di metadati:

SELECT 
    IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
    IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
    IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
    UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
    SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);

Risultato

Le due proprietà di accesso ai dati sono state impostate su true e le altre tre sono impostate su false .

Ciò ha implicazioni oltre a quelle che ci si potrebbe aspettare (ad esempio, utilizzare in viste indicizzate o colonne calcolate indicizzate).

Effetti su Query Optimizer

La proprietà Determinism in particolare influisce su Query Optimizer. Ha regole dettagliate riguardanti i tipi di riscritture e manipolazioni che può eseguire, e queste sono molto limitate per gli elementi non deterministici. Gli effetti collaterali possono essere abbastanza sottili.

Ad esempio, considerare le due tabelle seguenti:

CREATE TABLE dbo.T1
(
    SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
    SomeDate datetime PRIMARY KEY
);

... e una query che utilizza la funzione (come definita in precedenza):

SELECT * 
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = dbo.F(T1.SomeInteger);

Il piano di query è come previsto, con una ricerca nella tabella T2:

Cerca un piano

Tuttavia, se la stessa query logica viene scritta utilizzando una tabella derivata o un'espressione di tabella comune:

WITH CTE AS
(
    SELECT *, dt = dbo.F(T1.SomeInteger) 
    FROM dbo.T1 AS T1
)
SELECT * 
FROM CTE
JOIN dbo.T2 AS T2
    ON T2.SomeDate = CTE.dt;

-- Derived table
SELECT
    *
FROM 
(
    SELECT *, dt = dbo.F(T1.SomeInteger)
    FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = T1.dt;

Il piano di esecuzione ora presenta una scansione, con il predicato che coinvolge la funzione bloccata in un filtro:

Piano di scansione

Ciò accade anche se la tabella derivata o l'espressione di tabella comune viene sostituita da una vista o una funzione in linea. Un FORCESEEKsuggerimento (e altri tentativi simili) non avrà esito positivo:

Messaggio di errore

Il problema fondamentale è che Query Optimizer non può riordinare gli elementi di query non deterministici come liberamente .

Per produrre una ricerca, il predicato Filter dovrebbe essere spostato nel piano per accedere ai dati T2. Questo movimento è impedito quando la funzione non è deterministica.

fix

La correzione per questo esempio prevede due passaggi:

  1. Inserisci WITH SCHEMABINDING
  2. Rendi deterministica la funzione

Il primo passo è banale. Il secondo implica la rimozione del cast implicito non deterministico dalla stringa a datetime; sostituendolo con un deterministico CONVERT. Nessuno dei due è sufficiente da solo .

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CONVERT(datetime, '19000101', 112);
END;

Le proprietà della funzione sono ora:

Nuove proprietà

Con l'ottimizzatore liberato, tutti gli esempi ora producono il piano di ricerca desiderato .


Si noti che l'utilizzo di un CASTto datetimenella funzione non funzionerebbe, poiché non è possibile specificare uno stile di conversione in quella sintassi:

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CAST('19000101' AS datetime);
END;

Questa definizione di funzione produce il piano di scansione e le proprietà mostrano che rimane non deterministico:

Proprietà della funzione CAST

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.