Durante la creazione del profilo di un database mi sono imbattuto in una vista che fa riferimento ad alcune funzioni non deterministiche a cui si accede 1000-2500 volte al minuto per ogni connessione nel pool di questa applicazione. Un semplice SELECT
dalla vista produce il seguente piano di esecuzione:
Sembra un piano complesso per una vista che ha meno di mille righe che possono vedere una o due righe cambiare ogni pochi mesi. Ma peggiora con le seguenti altre osservanze:
- Le viste nidificate non sono deterministiche, quindi non possiamo indicizzarle
- Ogni vista fa riferimento a più
UDF
s per creare le stringhe - Ogni UDF contiene messaggi nidificati
UDF
per ottenere i codici ISO per le lingue localizzate - Le viste nello stack utilizzano costruttori di stringhe aggiuntivi restituiti da
UDF
s comeJOIN
predicati - Ogni stack di vista viene trattato come una tabella, il che significa che ci sono
INSERT
/UPDATE
/DELETE
trigger su ciascuno per scrivere nelle tabelle sottostanti - Questi trigger sulle viste utilizzano
CURSORS
che leEXEC
stored procedure che fanno riferimento più di questi archi dell'edificioUDF
s.
Questo mi sembra abbastanza marcio, ma ho solo pochi anni di esperienza con TSQL. Anche meglio!
Sembra che lo sviluppatore che abbia deciso che questa fosse un'ottima idea, abbia fatto tutto ciò in modo che le poche centinaia di stringhe memorizzate possano avere una traduzione basata su una stringa restituita da una UDF
specifica dello schema.
Ecco una delle viste nello stack, ma sono tutte ugualmente cattive:
CREATE VIEW [UserWKStringI18N]
AS
SELECT b.WKType, b.WKIndex
, CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.I18NString
ELSE il.I18nString
END AS WKString
,CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.IETFLangCode
ELSE il.IETFLangCode
END AS IETFLangCode
,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS') AS I18NID
,dbo.UserI18N_Session_Locale_Key() AS IETFSessionLangCode
,dbo.UserI18N_Database_Locale_Key() AS IETFDatabaseLangCode
FROM UserWKStringBASE b
LEFT OUTER JOIN User3StringI18N il
ON (
il.I18NID = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS')
AND il.IETFLangCode = dbo.UserI18N_Session_Locale_Key()
)
LEFT OUTER JOIN User3StringI18N id
ON (
id.I18NID = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex,N'WKS')
AND id.IETFLangCode = dbo.UserI18N_Database_Locale_Key()
)
GO
Ecco perché UDF
vengono usati come JOIN
predicati. La I18NID
colonna è formata concatenando:STRING + [ + ID + | + ID + ]
Durante il test di questi, un semplice SELECT
dalla vista restituisce ~ 309 righe e richiede 900-1400ms per l'esecuzione. Se scarico le stringhe in un'altra tabella e schiaffo un indice su di essa, la stessa selezione ritorna in 20-75ms.
Quindi, per farla breve (e spero che abbiate apprezzato un po 'di questa sciocchezza) Voglio essere un buon samaritano e riprogettare e riscrivere questo per il 99% dei clienti che gestiscono questo prodotto che non usano affatto alcuna localizzazione- - gli utenti dovrebbero utilizzare le [en-US]
impostazioni locali anche quando l'inglese è una seconda / terza lingua.
Dal momento che si tratta di un trucco non ufficiale, sto pensando a quanto segue:
- Creare una nuova tabella String popolata con un set di dati unito correttamente dalle tabelle di base originali
- Indicizza la tabella.
- Creare un set di sostituzione di viste di livello superiore nello stack che includa
NVARCHAR
eINT
colonne per le colonneWKType
eWKIndex
. - Modifica una manciata di
UDF
s che fanno riferimento a queste viste per evitare conversioni di tipo in alcuni predicati di join (la nostra tabella di controllo più grande è di 500-2.000 M righe e ne memorizza unaINT
in unaNVARCHAR(4000)
colonna che viene utilizzata per unire contro laWKIndex
colonna (INT
).) - Schemabind le viste
- Aggiungi alcuni indici alle viste
- Ricostruisci i trigger sulle viste usando set logic anziché cursori
Ora, le mie domande attuali:
- Esiste un metodo di best practice per gestire stringhe localizzate tramite una vista?
- Quali alternative esistono per usare a
UDF
come stub? (Posso scrivere uno specificoVIEW
per ciascun proprietario dello schema e codificare la lingua invece di fare affidamento su una varietà diUDF
stub.) - Queste viste possono essere semplicemente rese deterministiche qualificando completamente le
UDF
s nidificate e quindi schematizzando le pile di viste?
UDF
definizione. Inoltre, fai riferimento a Funzioni definite dall'utente T-SQL: il buono, il brutto e il cattivo