Pergunta

Eu tenho um simples exibição indexado. Quando eu consultar contra ela, é muito lento. Primeiro eu mostrar-lhe do esquema e índices. Em seguida, a simples consulta. Finalmente um screnie plano de consulta.

Update:. Prova de solução no final deste post

Esquema

Este é o que parece: -

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

Meu UDF ToUriCleanText apenas substitui vários personagens com um caractere vazio. Por exemplo. substitui todos os caracteres '#' com ''.

Então eu adicionei dois índices sobre isso: -

Índices

índice de chave primária (ie. Índice de cluster)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

E um índice não agrupado

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Agora, isso tem cerca de 25 mil linhas. grande nada.

Quando eu faço o seguinte consultas, ambos demorar cerca de quatro segundo estranho. WTF? Este deve ser .. basicamente instantânea!

Consulta 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

Consulta 2 (acrescentado um outro onde o item cláusula)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

O que eu fiz de errado? É a UDF estragar as coisas? Eu pensei que, porque eu tenho index'd este ponto de vista, seria materializado. Como tal, não teria que calcular essa coluna string.

Aqui está uma screenie do plano de consulta, se isso ajuda: - text alt

Além disso, observe o índice que ele está usando? Por que é usando esse índice?

Esse índice é ...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Então, sim, todas as idéias gente?

Update 1:. Esquema Adicionado para o UDF

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '$', ''), etc.
END

Update 2: Solução

Sim, era porque eu não estava usando o índice na vista e teve que fazer manualmente certeza que eu não expandir a vista. O servidor é o SQL Server 2008 Standard Edition. A resposta completa está abaixo. Aqui está a prova, WITH (NOEXPAND) text alt

Obrigado a todos por me ajudar a resolver este problema:)

Foi útil?

Solução

O que edição do SQL Server? Eu acredito que só Empresa e Developer Edition irá usar exibições indexadas automaticamente, enquanto os outros apoiá-lo usando dicas de consulta.

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

A partir dicas de consulta (Transact SQL) no MSDN :

A exibição indexada não é expandido somente se a visão está diretamente referenciada na parte SELECT da consulta e COM (NOEXPAND) ou COM (NOEXPAND, INDEX (index_value [, ... n])) é especificado.

Outras dicas

Eu vejo um sinal @ no código de consulta no seu plano de execução. Há uma variável de cadeia envolvida.

Sql Server tem um comportamento desagradável se o tipo da variável string não corresponder ao tipo da coluna string no índice. SQL Server irá ... converter toda a coluna a esse modelo, executar a pesquisa rápida e, em seguida, jogar fora o índice convertido para que ele possa fazer a coisa toda novamente na próxima consulta.


Simon percebi isso - mas aqui é mais útil detalhe: http: // msdn.microsoft.com/en-us/library/ms187373.aspx

Se uma consulta contém referências a colunas que estão presentes tanto em uma visão e base indexados tabelas e o otimizador de consulta determina que o uso da exibição indexada fornece o melhor método para executar a consulta, o otimizador de consulta usa o índice na vista . Esta função é chamada indexada correspondência vista , e é suportado apenas no SQL Server Enterprise e edições para desenvolvedores.

No entanto, para o otimizador considerar exibições indexadas para correspondência ou usar uma exibição indexada que é referenciado com a dica NOEXPAND, as seguintes opções SET deve ser definido como ON:

Então, o que está acontecendo aqui é que indexada correspondência vista não está funcionando. Certifique-se de que você está usando o Enterprise ou Developer Edition do SQL Server (muito provável). Em seguida, verifique suas opções definidas de acordo com o artigo.

Recentemente construiu uma grande base de dados com centenas de milhões de registros de detalhes de chamadas e existem algumas funções que eu estava usando em consultas e vistas que eu transformadas em colunas computadas persistiram. Isso funcionou muito melhor, porque eu poderia índice na coluna computada.

Eu não estava usando SQL Enterprise embora assim que eu não tive a oportunidade de usar exibições indexadas. É a exibição indexada suposto ser capaz de indexar os resultados determinísticos da UDF?

Eu suspeito que ele tem que chamar essa função para cada linha antes que ele possa fazer a comparação em sua cláusula WHERE. Eu expor assunto, executar a verificação de consulta em relação a isso diretamente e ver como os tempos trabalhar fora. Eu geralmente visto muita lentidão sempre que modificar um valor usando uma função e, em seguida, usá-lo na cláusula onde ...

Qual o benefício que você está procurando usando uma exibição indexada? Não é possível corretamente índice da tabela (s) a si mesmos? Sem uma boa justificação, você está adicionando complexidade e pedindo o otimizador para lidar com mais objetos de banco de dados com menos flexibilidade.

Você já avaliou a mesma lógica de consulta com índices padrão?

mistura em UDF turva lógica as coisas ainda mais.

Se tudo que você quer é a persistir o valor de retorno de um UDF, considere uma persistiu coluna computada em vez de uma exibição indexada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top