Ao criar um perfil de um banco de dados, deparei-me com uma visão que faz referência a algumas funções não determinísticas que são acessadas de 1000 a 2500 vezes por minuto para cada conexão no pool desse aplicativo. Um simples SELECT
da visualização gera o seguinte plano de execução:
Esse parece ser um plano complexo para uma exibição com menos de mil linhas que podem exibir uma ou duas linhas mudar a cada poucos meses. Mas piora com as seguintes outras observâncias:
- As visualizações aninhadas não são determinísticas, portanto, não podemos indexá-las
- Cada visualização faz referência a vários
UDF
s para construir as strings - Cada UDF contém
UDF
s aninhados para obter os códigos ISO para idiomas localizados - As visualizações na pilha estão usando construtores de sequência adicionais retornados de
UDF
s comoJOIN
predicados - Cada pilha de visualizações é tratada como uma tabela, o que significa que há
INSERT
/UPDATE
/DELETE
gatilhos em cada um para gravar nas tabelas subjacentes - Esses gatilhos nas vistas usar
CURSORS
que osEXEC
procedimentos armazenados que fazem referência mais destes corda edifícioUDF
s.
Isso me parece muito ruim, mas eu tenho apenas alguns anos de experiência com o TSQL. Fica melhor também!
Parece que o desenvolvedor que decidiu que essa era uma ótima idéia fez tudo isso para que as poucas centenas de strings armazenadas possam ter uma tradução baseada em uma string retornada de uma UDF
específica do esquema.
Aqui está uma das visualizações na pilha, mas todas são igualmente ruins:
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
Aqui está o porquê de os UDF
s serem usados como JOIN
predicados. A I18NID
coluna é formada concatenando:STRING + [ + ID + | + ID + ]
Durante o teste, um simples SELECT
da exibição retorna ~ 309 linhas e leva 900-1400ms para ser executado. Se eu colocar as strings em outra tabela e colocar um índice nela, a mesma seleção retornará em 20-75ms.
Portanto, para encurtar a história (e espero que você tenha gostado um pouco dessa bobagem), quero ser um bom samaritano, redesenhar e reescrever isso para os 99% dos clientes que executam este produto que não usam nenhuma localização - Espera-se que os usuários finais usem o [en-US]
código do idioma mesmo quando o inglês for um segundo / terceiro idioma.
Como esse é um hack não oficial, estou pensando no seguinte:
- Crie uma nova tabela String preenchida com um conjunto de dados unido de forma limpa a partir das tabelas base originais
- Indexar a tabela.
- Crie um conjunto de visualizações de nível superior na pilha que inclua
NVARCHAR
eINT
colunas para as colunasWKType
eWKIndex
. - Modifique um punhado de
UDF
s que fazem referência a essas visualizações para evitar conversões de tipo em alguns predicados de junção (nossa maior tabela de auditoria tem 500-2.000M de linhas e armazena umINT
em umaNVARCHAR(4000)
coluna que é usada para ingressar naWKIndex
coluna (INT
).) - Esquemabind as visualizações
- Adicione alguns índices às visualizações
- Reconstrua os gatilhos nas visualizações usando lógica de conjunto em vez de cursores
Agora, minhas perguntas reais:
- Existe um método de prática recomendada para lidar com seqüências de caracteres localizadas por meio de uma exibição?
- Quais alternativas existem para usar a
UDF
como um esboço? (Eu posso escrever um específicoVIEW
para cada proprietário do esquema e codificar a linguagem em vez de confiar em uma variedade deUDF
stubs.) - Essas visualizações podem ser simplesmente tornadas determinísticas, qualificando totalmente os se aninhados
UDF
e depois vinculando o esquema às pilhas de visualizações?
UDF
definição também. Além disso, referem-se a T-SQL funções definidas pelo usuário: o bom, o mau eo feioRespostas:
Olhando para o código fornecido, podemos dizer:
Segundo, o UDF não deve ser chamado com frequência para a mesma coluna. Aqui, é chamado uma vez no select
e Segunda vez para ingressar
É possível gerar valores em uma tabela temporária ou usar uma CTE (Common Table Expression) para obter esses valores em primeiro lugar antes que a junção ocorra.
Eu criei uma amostra da USP que fornecerá algumas melhorias:
Por favor tente isto
fonte