Al perfilar una base de datos, me encontré con una vista que hace referencia a algunas funciones no deterministas a las que se accede 1000-2500 veces por minuto para cada conexión en el grupo de esta aplicación. Un simple SELECT
desde la vista produce el siguiente plan de ejecución:
Parece un plan complejo para una vista que tiene menos de mil filas que pueden ver una o dos filas cambiar cada pocos meses. Pero empeora con las siguientes otras observancias:
- Las vistas anidadas no son deterministas, por lo que no podemos indexarlas
- Cada vista hace referencia a múltiples
UDF
s para construir las cadenas - Cada UDF contiene
UDF
s anidados para obtener los códigos ISO para idiomas localizados - Las vistas en la pila están utilizando constructores de cadenas adicionales devueltos por
UDF
s comoJOIN
predicados - Cada pila de vista se trata como una tabla, lo que significa que hay
INSERT
/UPDATE
/DELETE
disparadores en cada una para escribir en las tablas subyacentes - Estos factores desencadenantes de las vistas utilizan
CURSORS
que losEXEC
procedimientos almacenados que hacen referencia a más de estas cuerdas edificioUDF
s.
Esto me parece bastante malo, pero solo tengo unos años de experiencia con TSQL. ¡También se pone mejor!
Parece que el desarrollador que decidió que esta era una gran idea, hizo todo esto para que los cientos de cadenas que se almacenan puedan tener una traducción basada en una cadena devuelta desde un UDF
esquema específico.
Aquí hay una de las vistas en la pila, pero todas son igualmente malas:
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
Aquí es por qué UDF
s se utilizan como JOIN
predicados. La I18NID
columna se forma concatenando:STRING + [ + ID + | + ID + ]
Durante la prueba de estos, un simple SELECT
desde la vista devuelve ~ 309 filas y tarda 900-1400ms en ejecutarse. Si vuelco las cadenas en otra tabla y le doy un índice, la misma selección regresa en 20-75 ms.
Así que, para resumir (y espero que hayan apreciado algo de esta tontería), quiero ser un buen samaritano y rediseñar y reescribir esto para el 99% de los clientes que ejecutan este producto y que no utilizan ninguna localización en absoluto. Se espera que los usuarios finales usen la [en-US]
configuración regional incluso cuando el inglés es un segundo / tercer idioma.
Dado que este es un truco no oficial, estoy pensando en lo siguiente:
- Cree una nueva tabla de Cadena rellenada con un conjunto de datos limpiamente unidos de las tablas base originales
- Indice la tabla.
- Cree un conjunto de reemplazo de vistas de nivel superior en la pila que incluya columnas
NVARCHAR
yINT
para las columnasWKType
yWKIndex
. - Modifique un puñado de
UDF
correos electrónicos que hagan referencia a estas vistas para evitar conversiones de tipos en algunos predicados de unión (nuestra tabla de auditoría más grande es de 500-2,000M filas y almacena unaINT
en unaNVARCHAR(4000)
columna que se usa para unirse contra laWKIndex
columna (INT
)). - Schemabind las vistas
- Agregue algunos índices a las vistas.
- Reconstruya los desencadenantes en las vistas usando la lógica establecida en lugar de los cursores
Ahora, mis preguntas reales:
- ¿Existe un método de mejores prácticas para manejar cadenas localizadas a través de una vista?
- ¿Qué alternativas existen para usar a
UDF
como trozo? (Puedo escribir un específicoVIEW
para cada propietario de esquema y codificar el idioma en lugar de confiar en una variedad deUDF
stubs). - ¿Pueden estas vistas hacerse simplemente deterministas al calificar completamente los
UDF
sy anidados y luego vincular esquemáticamente las pilas de vistas?
UDF
definición también. Además, consulte Funciones definidas por el usuario de T-SQL: lo bueno, lo malo y lo feo