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 SELECTdesde 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
UDFs para construir las cadenas - Cada UDF contiene
UDFs anidados para obtener los códigos ISO para idiomas localizados - Las vistas en la pila están utilizando constructores de cadenas adicionales devueltos por
UDFs comoJOINpredicados - Cada pila de vista se trata como una tabla, lo que significa que hay
INSERT/UPDATE/DELETEdisparadores en cada una para escribir en las tablas subyacentes - Estos factores desencadenantes de las vistas utilizan
CURSORSque losEXECprocedimientos almacenados que hacen referencia a más de estas cuerdas edificioUDFs.
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 UDFesquema 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é UDFs se utilizan como JOINpredicados. La I18NIDcolumna se forma concatenando:STRING + [ + ID + | + ID + ]
Durante la prueba de estos, un simple SELECTdesde 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
NVARCHARyINTpara las columnasWKTypeyWKIndex. - Modifique un puñado de
UDFcorreos 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 unaINTen unaNVARCHAR(4000)columna que se usa para unirse contra laWKIndexcolumna (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
UDFcomo trozo? (Puedo escribir un específicoVIEWpara cada propietario de esquema y codificar el idioma en lugar de confiar en una variedad deUDFstubs). - ¿Pueden estas vistas hacerse simplemente deterministas al calificar completamente los
UDFsy anidados y luego vincular esquemáticamente las pilas de vistas?





UDFdefinición también. Además, consulte Funciones definidas por el usuario de T-SQL: lo bueno, lo malo y lo feoRespuestas:
Mirando el código dado, podemos decir:
En segundo lugar, el UDF no debe llamarse con frecuencia para la misma columna. Aquí, se llama una vez en la selección
y segunda vez para unirse
Se pueden generar valores en una tabla temporal o usar un CTE (expresión de tabla común) para obtener esos valores en primer lugar antes de que se realice la unión.
He generado una muestra de USP que proporcionará algunas mejoras:
Por favor intente esto
fuente