Grande differenza di prestazioni (da 1 ora a 1 minuto) rilevata in SQL. Puoi spiegare perché?
-
10-07-2019 - |
Domanda
Le seguenti query richiedono rispettivamente 70 minuti e 1 minuto su una macchina standard per 1 milione di record. Quali potrebbero essere le possibili ragioni?
Query [01:10:00]
SELECT *
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
ELSE sys.fn_cdc_increment_lsn(0x00) END
, sys.fn_cdc_get_max_lsn()
, 'all with mask')
WHERE __$operation <> 1
Query modificata [00:01:10]
DECLARE @MinLSN binary(10)
DECLARE @MaxLSN binary(10)
SELECT @MaxLSN= sys.fn_cdc_get_max_lsn()
SELECT @MinLSN=CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
ELSE sys.fn_cdc_increment_lsn(0x00) END
SELECT *
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
@MinLSN, @MaxLSN, 'all with mask') WHERE __$operation <> 1
[Modificato]
Ho provato a ricreare lo scenario con una funzione simile per vedere se i parametri sono valutati per ogni riga.
CREATE FUNCTION Fn_Test(@a decimal)RETURNS TABLE
AS
RETURN
(
SELECT @a Parameter, Getdate() Dt, PartitionTest.*
FROM PartitionTest
);
SELECT * FROM Fn_Test(RAND(DATEPART(s,GETDATE())))
Ma sto ottenendo lo stesso valore per la colonna "Parametro" per un milione di record elaborati in 38 secondi.
Soluzione
Anche le funzioni scalari deterministiche vengono valutate almeno una volta per riga. Se la stessa funzione scalare deterministica si verifica più volte sulla stessa "riga" con gli stessi parametri, credo che solo allora verrà valutata una volta - ad es. in un CASO QUANDO fn_X (a, b, c) > 0 THEN fn_X (a, b, c) ELSE 0 END
o qualcosa del genere.
Penso che il tuo problema RAND sia dovuto al fatto che continui a ridimensionare:
Chiamate ripetitive di RAND () con il lo stesso valore seme restituisce lo stesso risultati.
Per una connessione, se RAND () è chiamato con un valore seme specificato, tutte le successive chiamate di RAND () producono risultati basati sul seme RAND () chiamata. Ad esempio, la seguente query restituirà sempre la stessa sequenza di numeri.
Ho preso in considerazione la memorizzazione nella cache dei risultati delle funzioni scalari, come hai indicato, anche arrivando al punto di precalcolare le tabelle dei risultati delle funzioni scalari e di unirmi a loro. Qualcosa deve essere fatto alla fine per far funzionare le funzioni scalari. Altrimenti, l'opzione migliore è il CLR - apparentemente questi UDF SQL superano di gran lunga. Sfortunatamente, non posso usarli nel mio ambiente attuale.
Altri suggerimenti
Nella prima query, fn_cdc_increment_lsn
e fn_cdc_get_min_lsn
vengono eseguiti per ogni riga. Nel secondo esempio, solo una volta.