Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Cosa posso fare per migliorare le prestazioni della mia funzione definita dall'utente pura in SQL Server?

Il mio primo pensiero qui è:qual è il problema delle prestazioni? Sicuramente hai un ciclo (una volta per riga per applicare dove) all'interno di un ciclo che esegue una query. Ma stai ricevendo piani di esecuzione scadenti? I tuoi set di risultati sono enormi? Ma passiamo al generico. Come risolve una volta questo problema? SQL non esegue la memorizzazione (come sottolinea l'illustre @Martin_Smith). Allora cosa deve fare un ragazzo?

Opzione 1 - Nuovo design

Crea un design completamente nuovo. In questo caso specifico @Aaron_Bertrand sottolinea che una tabella del calendario potrebbe soddisfare le tue esigenze. Giusto. Questo non ti aiuta in situazioni non di calendario, ma come spesso accade in SQL devi pensare in modo un po' diverso.

Opzione 2 - Chiama meno l'UDF

Restringere l'insieme di elementi che chiamano questa funzione. Questo mi ricorda molto come fare con successo impaginazione/conteggio righe . Genera un piccolo set di risultati con i valori distinti richiesti e poi chiama il tuo UDF in modo che venga chiamato solo poche volte. Questa può essere o meno un'opzione, ma può funzionare in molti scenari.

Opzione 3 - UDF dinamico

Probabilmente verrò fischiato fuori dalla stanza per questo suggerimento, ma ecco qui. Ciò che rende lenta questa UDF è l'istruzione select all'interno del ciclo. Se il tuo tavolo delle vacanze cambia davvero di rado, potresti mettere un trigger sul tavolo. Il trigger scriverebbe e aggiornerebbe UDF. Il nuovo UDF potrebbe forzare tutte le decisioni sulle vacanze. Sarebbe un po' come il cannibalismo con SQL che scrive SQL? Sicuro. Ma eliminerebbe la sottoquery e accelererebbe l'UDF. Che la polemica abbia inizio.

Opzione 4 - Memorizzalo!

Sebbene SQL non possa memorizzare direttamente, abbiamo SQL CLR. Converti l'UDF in un udf CLR SQL. In CLR puoi usare variabili statiche. Puoi facilmente prendere la tabella delle festività a intervalli regolari e archiviarla in una tabella hash. Quindi riscrivi il tuo ciclo nel CLR. Potresti anche andare oltre e memorizzare l'intera risposta se questa è la logica appropriata.

Aggiornamento:

Opzione 1 - Stavo davvero cercando di concentrarmi sul generale qui, non sulla funzione di esempio che hai usato sopra. Tuttavia, l'attuale design della tua UDF consente più chiamate alla tabella Holiday se ti capita di colpirne alcune di seguito. L'utilizzo di una sorta di tabella in stile calendario che contiene un elenco di "giorni negativi" e il corrispondente "giorno lavorativo successivo" ti consentirà di rimuovere il potenziale per più hit e query.

Opzione 3 - Sebbene il dominio sia sconosciuto in anticipo, potresti benissimo modificare la tua tabella delle vacanze. Per un determinato giorno festivo conterrebbe il successivo giorno lavorativo corrispondente. Da questi dati potresti sputare un UDF con un'istruzione case lunga (quando '5/5/2012' poi '5/14/2012' o qualcosa di simile) in basso. Questa strategia potrebbe non funzionare per tutti i tipi di problemi, ma potrebbe funzionare bene per alcuni tipi di problemi.

Opzione 4 - Ci sono implicazioni per ogni tecnologia. CLR deve essere distribuito, la configurazione di SQL Server modificata e SQL CLR è limitato al framework 3.5. Personalmente, ho trovato queste regolazioni abbastanza facili, ma la tua situazione potrebbe essere diversa (ad esempio un DBA recalcitrante o restrizioni sulle modifiche ai server di produzione).

L'utilizzo di variabili statiche richiede che gli assembly siano concessa la PIENA FIDUCIA . Dovrai assicurarti di avere il blocco corretto.

Ci sono alcune prove che a molto alto livelli di transazione CLR non funziona bene come SQL diretto. Nel tuo scenario, tuttavia, questa osservazione potrebbe non essere applicabile perché non esiste un correlato SQL diretto per ciò che stai cercando di fare (memoizzare).