Database
 sql >> Base de Dados >  >> RDS >> Database

As 3 principais dicas que você precisa saber para escrever visualizações SQL mais rápidas


Amigo ou inimigo? As visualizações do SQL Server foram objeto de debates acalorados quando eu estava no meu primeiro ano usando o SQL Server. Eles disseram que era ruim porque era lento. Mas e hoje?

Você está no mesmo barco que eu estava há muitos anos? Então, junte-se a mim nesta jornada para desvendar o verdadeiro negócio sobre visualizações SQL para que você possa escrevê-las o mais rápido possível.

As visualizações SQL são tabelas virtuais. Os registros em uma visualização são o resultado de uma consulta dentro dela. Sempre que as tabelas base usadas na visualização são atualizadas, ela também atualiza a visualização. Você também pode INSERT, UPDATE e DELETE registros em uma exibição como uma tabela em alguns casos. Embora eu não tenha tentado isso sozinho.

Da mesma forma que uma tabela, você pode CREATE, ALTER ou DROP uma view. Você pode até criar um índice, com algumas restrições.

Observe que usei o SQL Server 2019 nos códigos de exemplo.

1. Conheça o uso adequado e impróprio de visualizações SQL


Primeiro, o básico.

Para que servem as visualizações SQL?

É crucial. Se você usá-lo como um martelo para uma chave de fenda, esqueça as visualizações SQL mais rápidas. Primeiro, vamos relembrar o uso adequado:
  • Para focar, simplificar e personalizar a percepção que cada usuário tem do banco de dados.
  • Para permitir que os usuários acessem as únicas informações que eles precisam ver por motivos de segurança.
  • Para fornecer compatibilidade com versões anteriores a uma tabela antiga ou a um esquema antigo para não interromper aplicativos dependentes. É temporário até que todas as alterações necessárias sejam concluídas.
  • Para particionar dados provenientes de diferentes servidores. Portanto, eles aparecem como se fossem uma tabela de um servidor ou instância.

Como NÃO usar exibições do SQL Server?
  • Reutilize a visualização em outra visualização que será reutilizada em outra visualização. Em resumo, visualizações profundamente aninhadas. A reutilização de código tem algumas desvantagens neste caso.
  • Economize em pressionamentos de tecla. Relaciona-se com o primeiro, que reduz a pressão dos dedos e parece acelerar a codificação.

O uso impróprio de visualizações, se permitido, obscurecerá o verdadeiro motivo pelo qual você cria visualizações. Como você verá mais tarde, os benefícios reais superam os benefícios percebidos do uso inadequado.

Exemplo


Vamos inspecionar um exemplo da Microsoft. O vFuncionário vista da AdventureWorks . Aqui está o código:
-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee] 
AS 
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
 ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO

O objetivo dessa visão se concentra nas informações básicas do funcionário. Se necessário por uma equipe de recursos humanos, ele pode ser exibido em uma página da web. Foi reutilizado em outras visualizações?

Tente isto:
  1. No SQL Server Management Studio , procure o AdventureWorks banco de dados.
  2. Expandir a pasta Visualizações e procure por [HumanResources].[vEmployee].
  3. Clique com o botão direito do mouse e selecione Exibir dependências .

Se você vir outra exibição dependendo dessa exibição, que depende de uma exibição diferente, a Microsoft nos deu um mau exemplo. Mas então, não há outras dependências de exibição.

Vamos para o próximo.

2. Desmistifique o mito das visualizações SQL


Quando o SQL Server processa um SELECT from a view , ele avalia o código na visão ANTES de lidar com a cláusula WHERE ou qualquer junção na consulta externa. Com mais tabelas unidas, será mais lento comparado a um SELECT from base tables com os mesmos resultados.

Pelo menos, é o que me disseram quando comecei a usar SQL. Se é um mito ou não, só há uma maneira de descobrir. Vamos a um exemplo prático.

Como funcionam as visualizações SQL


A Microsoft não nos deixou no escuro para debater sem parar. Temos as ferramentas para ver como as consultas funcionam, como STATISTICS IO e o Plano de Execução Real . Vamos usá-los em todos os nossos exemplos. Vamos ter o primeiro.
USE AdventureWorks
GO

SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

Para ver o que está acontecendo quando o SQL Server processa a exibição, vamos inspecionar o Plano de Execução Real na Figura 1. Comparamos com o código CREATE VIEW para vEmployee na seção anterior.

Como você pode ver, os primeiros nós processados ​​pelo SQL Server são os que usam INNER JOIN. Em seguida, ele processa os LEFT OUTER JOINs.

Como não podemos ver um nó Filtro em nenhum lugar para a cláusula WHERE, ele deve estar em um desses nós. Se você inspecionar as propriedades de todos os nós, verá a cláusula WHERE processada na tabela Employee. Coloquei-o em uma caixa na Figura 1. Para provar que está lá, veja a Figura 2 para as Propriedades desse nó:

Análise


Então, tinha a instrução SELECT no vEmployee view foi avaliada ou processada ANTES da aplicação da cláusula WHERE? O Plano de Execução mostra que não. Se fosse, deveria aparecer mais próximo do nó SELECT.

O que me disseram era um mito. Eu estava evitando algo bom por causa de um mal-entendido sobre o uso adequado de visualizações SQL.

Agora que sabemos como o SQL Server processa um SELECT de uma exibição , a pergunta permanece:é mais lento do que não usar uma visualização?

SELECT FROM View vs. SELECT FROM Base Tables – Qual deles será executado mais rápido?


Primeiro, precisamos extrair a instrução SELECT dentro do vEmployee view e produzir o mesmo resultado que tivemos ao usar a view. O código abaixo mostra a mesma cláusula WHERE:
USE AdventureWorks
GO

-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

-- SELECT FROM Base Tables
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
	ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105

Em seguida, inspecionamos o STATISTICS IO e fazemos um Compare Showplan . De quantos recursos uma consulta de uma exibição precisará em comparação com a consulta de tabelas base? Consulte a Figura 3.

Aqui, a consulta de uma exibição ou de tabelas base consumirá as mesmas leituras lógicas. Ambos usaram páginas de 19 * 8 KB. Com base nisso, é um empate em quem é mais rápido. Em outras palavras, usar uma visualização não prejudicará o desempenho. Vamos comparar o Plano de Execução Real de ambos usando o Compare Showplan :

Você vê a parte sombreada do diagrama? Que tal o QueryPlanHash de ambos? Como ambas as consultas têm QueryPlanHash iguais e as mesmas operações, sejam as tabelas de visualização ou base serão processadas da mesma forma pelo SQL Server .

As mesmas leituras lógicas e o mesmo plano da amostra nos dizem que ambos terão o mesmo desempenho. Assim, ter leituras lógicas altas fará com que sua consulta seja executada lentamente, independentemente de você usar visualizações ou não. Conhecer este fato irá ajudá-lo a corrigir o problema e tornar sua visualização mais rápida.

Infelizmente, há algumas más notícias.

Juntar visualizações SQL a tabelas


O que você viu anteriormente é um SELECT de uma visão sem junções. No entanto, e se você unir uma tabela a uma exibição?

Vamos rever outro exemplo. Desta vez, usamos o vSalesPerson ver em AdventureWorks – uma lista de vendedores com informações de contato e cota de vendas. Novamente, comparamos a instrução com um SELECT das tabelas base:
-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT 
 sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName

-- using base tables
SELECT
 p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName 

Se você acha que também será o mesmo, verifique as ESTATÍSTICAS IO:

Surpreso? Participando do vSalesPerson visualizar com o SalesOrderHeader table precisa de recursos enormes (28.240 x 8 KB) em comparação com apenas usar as tabelas base (774 x 8 KB). Observe também que incluía algumas tabelas que não precisávamos (as tabelas dentro das caixas vermelhas). Muito menos leituras lógicas mais altas em SalesOrderHeader ao usar a visualização.

Mas não termina aí.

O Plano de Execução Real revela mais


Observe o Plano de Execução Real da consulta às tabelas base:

A ilustração parece mostrar um Plano de Execução bastante normal. Mas confira o que tem a vista:

O plano de execução na Figura 7 coincide com o STATISTICS IO na Figura 5. Podemos ver as tabelas que não precisamos na visualização. Há também uma Pesquisa de chave nó com uma estimativa de linha com mais de mil registros fora das linhas reais. Finalmente, um aviso no nó SELECT também aparece. O que poderia ser?

O que é isso ExcessiveGrant aviso no nó SELECT?

Uma concessão excessiva ocorre quando a memória máxima usada é muito pequena em comparação com a memória concedida. Nesse caso, 1024 KB foram concedidos, mas apenas 16 KB foram usados.

A concessão de memória é a quantidade estimada de memória em KB necessária para executar o plano.

Podem ser as estimativas erradas na Pesquisa de chave node e/ou a inclusão das tabelas que não precisávamos no plano que causou isso. Além disso, muita memória concedida pode causar bloqueio. Os 1008 KB restantes poderiam ter sido úteis para outras operações.

Eventualmente, algo deu errado quando você uniu a exibição com uma tabela. Não temos que lidar com esses problemas se consultarmos as tabelas base.

Recomendações


Foi uma longa explicação. No entanto, sabemos que as visualizações não são avaliadas ou processadas ANTES de uma cláusula WHERE ou junções na consulta externa serem avaliadas. Também provamos que ambos teriam o mesmo desempenho.

Por outro lado, há um caso em que juntamos uma view a uma tabela. Ele usa junções de tabelas que não precisamos da visão. Eles são invisíveis para nós, a menos que verifiquemos as ESTATÍSTICAS IO e o Plano de Execução Real. Tudo isso pode prejudicar o desempenho e os problemas podem surgir do nada.

Portanto:
  • Devemos saber como as consultas, incluindo visualizações, funcionam internamente.
  • O STATISTICS IO e os Planos de Execução Reais revelarão como as consultas e visualizações funcionarão.
  • Não podemos simplesmente unir uma visualização a uma tabela e reutilizá-la descuidadamente. Sempre verifique as ESTATÍSTICAS IO e os Planos de Execução Reais! Em vez de reutilizar visualizações e aninhá-las para uma produtividade de codificação “melhorada”, uso um IntelliSense e a ferramenta de preenchimento de código como SQL Complete.

Podemos, então, ter certeza de não escrever visualizações que terão resultados corretos, mas funcionarão como um caracol.

3. Experimente as visualizações indexadas


Visualizações indexadas são o que o nome indica. Ele pode aumentar o desempenho das instruções SELECT. Mas, como os índices de tabela, pode afetar o desempenho se as tabelas base forem grandes e atualizadas continuamente.

Para ver como as visualizações indexadas podem melhorar o desempenho da consulta, vamos examinar o vStateProvinceCountryRegion ver em AdventureWorks . A visualização está indexada em StateProvinceID e CountryRegionCode . É um índice único e agrupado.

Vamos comparar o STATISTICS IO da view que não tem o índice e tem um índice. Com isso, aprendemos quantas páginas de 8 KB nosso SQL Server irá ler:

A Figura mostra que ter um índice no vStateProvinceCountryRegion view reduz as leituras lógicas pela metade. É uma melhoria de 50% em relação a não ter um índice.

Isso é bom de ouvir.

Ainda assim, novamente, não adicione índices às suas visualizações descuidadamente. Além de ter uma longa lista de regras estritas para ter 1 índice único e clusterizado, isso pode prejudicar o desempenho, assim como adicionar índices a tabelas alegremente. Além disso, verifique o STATISTICS IO se houver uma diminuição nas leituras lógicas após adicionar o índice.

Recomendações


Como vimos em nosso exemplo, as visualizações indexadas podem melhorar o desempenho das visualizações SQL.

Dica BÔNUS


Assim como qualquer outra consulta, as visualizações SQL serão executadas rapidamente se:
  • As estatísticas são atualizadas
  • Índices ausentes são adicionados
  • Os índices são desfragmentados
  • Os índices usaram o FILLFACTOR certo

Conclusão


As visualizações SQL são boas ou ruins?

As visualizações SQL são boas se as escrevermos corretamente e verificarmos como elas serão processadas. Temos ferramentas como STATISTICS IO e Actual Execution Plan – use-as! Visualizações indexadas também podem melhorar o desempenho.

Gostou desta postagem? Por favor, compartilhe um pouco de amor em sua plataforma de mídia social favorita.