Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Três vitórias fáceis de desempenho do SQL Server


Como qualquer DBA de produção veterano sabe, muitas vezes você está sob pressão significativa para diagnosticar e aliviar os problemas de desempenho do banco de dados o mais rápido possível. Aqui estão três coisas que você pode aproveitar, dependendo de sua carga de trabalho e infraestrutura, para ter um impacto positivo muito perceptível no desempenho do banco de dados.

Ajuste básico do índice de armazenamento de linhas


A maioria das instâncias do SQL Server que encontrei em minha carreira teve algumas oportunidades de ajuste de índice de armazenamento de linhas relativamente fáceis. Uma coisa legal sobre o ajuste de índice de armazenamento de linhas é que ele está mais frequentemente sob seu controle direto como DBA, especialmente em comparação com o ajuste de consulta ou procedimento armazenado, que geralmente está sob o controle de desenvolvedores ou fornecedores de terceiros.

Alguns DBAs relutam em fazer qualquer ajuste de índice (especialmente em bancos de dados de terceiros) porque estão preocupados em quebrar algo ou comprometer o suporte do fornecedor para o banco de dados ou aplicativo. Obviamente, você precisa ter mais cuidado com bancos de dados de terceiros e tentar entrar em contato com o fornecedor antes de fazer qualquer alteração no índice, mas em algumas situações, você pode não ter outra alternativa viável (além de lançar hardware e armazenamento mais rápidos no problema ).

Você pode executar algumas consultas importantes de minhas consultas de informações de diagnóstico do SQL Server para ter uma boa ideia se tiver algumas oportunidades fáceis de ajuste de índice em sua instância ou banco de dados. Você deve estar atento a solicitações de índice ausentes, avisos de índice ausente, índices não clusterizados subutilizados ou não utilizados e possíveis oportunidades de compactação de dados.

É preciso alguma experiência, bom senso e conhecimento de sua carga de trabalho para fazer o ajuste de índice adequado. É muito comum ver pessoas fazendo ajustes de índice incorretos, fazendo muitas alterações de índice precipitadamente sem fazer a análise adequada.

Aqui estão algumas consultas que gosto de usar, no nível do banco de dados:
-- Missing Indexes for current database by Index Advantage  (Query 1) (Missing Indexes)
 
SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], 
  migs.last_user_seek, mid.[statement] AS [Database.Schema.Table],
  mid.equality_columns, mid.inequality_columns, mid.included_columns,
  migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact,
  OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows]
  FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
  INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
  ON migs.group_handle = mig.index_group_handle
  INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
  ON mig.index_handle = mid.index_handle
  INNER JOIN sys.partitions AS p WITH (NOLOCK)
  ON p.[object_id] = mid.[object_id]
  WHERE mid.database_id = DB_ID()
  AND p.index_id < 2 
  ORDER BY index_advantage DESC OPTION (RECOMPILE);
 
  ------
  -- Look at index advantage, last user seek time, number of user seeks to help determine source and importance
  -- SQL Server is overly eager to add included columns, so beware
  -- Do not just blindly add indexes that show up from this query!!!
 
  -- Find missing index warnings for cached plans in the current database  (Query 2) (Missing Index Warnings)
  -- Note: This query could take some time on a busy instance
 
  SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName], 
                 cp.objtype, cp.usecounts, cp.size_in_bytes, query_plan
  FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK)
  CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
  WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%'
  AND dbid = DB_ID()
  ORDER BY cp.usecounts DESC OPTION (RECOMPILE);
 
  ------
  -- Helps you connect missing indexes to specific stored procedures or queries
  -- This can help you decide whether to add them or not
  -- Possible Bad NC Indexes (writes >= reads)  (Query 3) (Bad NC Indexes)
 
  SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id, 
  i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor,
  s.user_updates AS [Total Writes], s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads],
  s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference]
  FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK)
  INNER JOIN sys.indexes AS i WITH (NOLOCK)
  ON s.[object_id] = i.[object_id]
  AND i.index_id = s.index_id
  WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1
  AND s.database_id = DB_ID()
  AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups)
  AND i.index_id > 1 AND i.[type_desc] = N'NONCLUSTERED'
  AND i.is_primary_key = 0 AND i.is_unique_constraint = 0 AND i.is_unique = 0
  ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE);
 
  ------
  -- Look for indexes with high numbers of writes and zero or very low numbers of reads
  -- Consider your complete workload, and how long your instance has been running
  -- Investigate further before dropping an index!
  -- Breaks down buffers used by current database by object (table, index) in the buffer cache  (Query 4) (Buffer Usage)
  -- Note: This query could take some time on a busy instance
  SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id, 
  CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)],  
  COUNT(*) AS [BufferCount], p.[Rows] AS [Row Count],
  p.data_compression_desc AS [Compression Type]
  FROM sys.allocation_units AS a WITH (NOLOCK)
  INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK)
  ON a.allocation_unit_id = b.allocation_unit_id
  INNER JOIN sys.partitions AS p WITH (NOLOCK)
  ON a.container_id = p.hobt_id
  WHERE b.database_id = CONVERT(int, DB_ID())
  AND p.[object_id] > 100
  AND OBJECT_NAME(p.[object_id]) NOT LIKE N'plan_%'
  AND OBJECT_NAME(p.[object_id]) NOT LIKE N'sys%'
  AND OBJECT_NAME(p.[object_id]) NOT LIKE N'xml_index_nodes%'
  GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows]
  ORDER BY [BufferCount] DESC OPTION (RECOMPILE);
 
  ------
  -- Tells you what tables and indexes are using the most memory in the buffer cache
  -- It can help identify possible candidates for data compression

Usando a durabilidade atrasada


O recurso de durabilidade atrasada foi adicionado ao produto no SQL Server 2014, portanto, está disponível há algum tempo. Confirmações de transações duráveis ​​atrasadas são assíncronas e relatam uma confirmação de transação como bem-sucedida antes os registros de log da transação são realmente gravados no subsistema de armazenamento. As transações duráveis ​​atrasadas não se tornam realmente duráveis ​​até que as entradas do log de transações sejam liberadas para o disco.

Esse recurso está disponível em todas as edições do SQL Server. Apesar disso, raramente o vejo sendo usado quando olho para bancos de dados de clientes. A durabilidade atrasada abre a possibilidade de alguma perda de dados, até um buffer de log inteiro no pior cenário (como explicado por Paul Randal aqui), portanto, definitivamente não é apropriado para um cenário de RPO onde absolutamente nenhuma perda de dados é aceitável.

A durabilidade atrasada reduz a latência da transação porque não espera que o log IO termine e retorne o controle ao cliente, além de reduzir o bloqueio e a contenção de disco para transações simultâneas. Esses dois benefícios geralmente podem ter um efeito muito positivo no desempenho da consulta e do aplicativo com a carga de trabalho de gravação muito pesada apropriada.

A durabilidade atrasada geralmente ajuda cargas de trabalho pesadas do tipo OLTP que têm transações de gravação muito frequentes e pequenas, nas quais você está vendo alta latência de gravação no nível do arquivo de sys.dm_io_virtual_file_stats no arquivo de log de transações e/ou está vendo altas esperas de WRITELOG de sys. dm_os_wait_stats.

Você pode facilmente forçar o SQL Server 2014 ou mais recente a usar a durabilidade atrasada para todas as transações (sem alterações de código) executando o seguinte comando:
ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;

Já tive clientes que ativam e desativam programaticamente a durabilidade atrasada em diferentes momentos do dia (como durante o ETL programado ou atividade de manutenção). Também tive clientes que usam durabilidade atrasada o tempo todo, pois têm uma carga de trabalho adequada e tolerância ao risco de perda de dados.

Finalmente, tive clientes que nunca considerariam o uso de durabilidade atrasada ou simplesmente não precisam disso com sua carga de trabalho. Se você suspeitar que sua carga de trabalho pode beneficiar do uso de durabilidade atrasada, mas você está preocupado com a possível perda de dados, existem outras alternativas que você pode considerar.

Uma alternativa é o recurso de buffer de log persistente no SQL Server 2016 SP1, onde você pode criar um segundo arquivo de log de transações de 20 MB em um volume de armazenamento de modo de acesso direto (DAX) hospedado em um dispositivo de memória persistente NV-DIMM. Esse arquivo de log de transação extra é usado para armazenar em cache o final do log, com acesso em nível de byte que ignora a pilha de armazenamento em nível de bloco convencional.

Se você acha que sua carga de trabalho pode se beneficiar do uso do recurso de buffer de log persistente, experimente usar temporariamente a durabilidade atrasada para ver se há um benefício real de desempenho com sua carga de trabalho antes de gastar o dinheiro na memória persistente NV-DIMM que você precisaria usar o recurso de buffer de log persistente.

Movendo o tempdb para o armazenamento Intel Optane DC P4800X


Tive grande sucesso com vários clientes recentes que moveram seus arquivos de banco de dados tempdb de algum outro tipo de armazenamento para uma unidade lógica apoiada por algumas placas de armazenamento Intel Optane DC P4800X PCIe NVMe (em uma matriz RAID 1 de software).

Esses cartões de armazenamento estão disponíveis em capacidades de 375 GB, 750 GB e 1,5 TB (embora a capacidade de 1,5 TB seja nova e ainda difícil de encontrar). Eles têm latência extremamente baixa (muito menor do que qualquer tipo de armazenamento flash NAND), excelente desempenho de E/S aleatória em profundidades de fila baixas (muito melhor do que o armazenamento flash NAND), com tempos de resposta de leitura consistentes sob uma carga de trabalho de gravação muito pesada.

Eles também têm maior resistência de gravação do que o armazenamento flash NAND corporativo de “gravação intensiva” e seu desempenho não se deteriora, pois estão perto de ficar cheios. Essas características tornam esses cartões extremamente adequados para muitas cargas de trabalho pesadas de tempdb, particularmente cargas de trabalho OLTP pesadas e situações em que você está usando RCSI em seus bancos de dados de usuário (o que coloca a carga de trabalho de armazenamento de versão resultante em tempdb).

Também é muito comum ver alta latência de gravação em nível de arquivo em arquivos de dados tempdb do DMV sys.dm_io_virtual_file_stats, portanto, mover seus arquivos de dados tempdb para o armazenamento Optane é uma maneira de resolver diretamente esse problema, que pode ser mais rápido e fácil do que o convencional ajuste de carga de trabalho.

Outro uso possível para os cartões de armazenamento Optane é como um lar para o(s) seu(s) arquivo(s) de log de transações. Você também pode usar o armazenamento Optane com versões herdadas do SQL Server (desde que seu sistema operacional e hardware o suportem). É uma alternativa possível ao uso de durabilidade atrasada (que requer o SQL Server 2014) ou ao uso do recurso de buffer de log persistente (que requer o SQL Server 2016 SP1).

Conclusão


Discuti três técnicas para obter uma vitória rápida de desempenho com o SQL Server:
  • O ajuste de índice de armazenamento de linhas convencional é aplicável a todas as versões do SQL Server e é uma das melhores ferramentas em seu arsenal.
  • A durabilidade atrasada está disponível no SQL Server 2014 e mais recente e pode ser muito benéfica com alguns tipos de carga de trabalho (e requisitos de RPO). O buffer de log persistente está disponível no SQL Server 2016 SP1 e oferece benefícios semelhantes como durabilidade atrasada, sem o perigo de perda de dados.
  • A movimentação de determinados tipos de arquivos de banco de dados para o armazenamento Intel Optane pode ajudar a aliviar os problemas de desempenho com tempdb ou com arquivos de log de transações do banco de dados do usuário. Você pode usar o armazenamento Optane com versões legadas do SQL Server e não são necessárias alterações de código ou configuração.