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

Suporte aprimorado para recriações de estatísticas paralelas


Uma das ótimas maneiras de aprender sobre bugs no SQL Server é ler as notas de versão das Atualizações Cumulativas e Service Packs quando elas forem lançadas. No entanto, ocasionalmente, essa também é uma ótima maneira de aprender sobre os aprimoramentos do SQL Server.

Atualização cumulativa 6 para SQL Server 2014 Service Pack 1 introduziu um novo sinalizador de rastreamento, 7471, que altera o comportamento de bloqueio de tarefas UPDATE STATISTICS no SQL Server (consulte KB #3156157). Neste post, veremos a diferença no comportamento de bloqueio e onde esse sinalizador de rastreamento pode ser útil.

Para configurar um ambiente de demonstração apropriado para este post, usei o banco de dados AdventureWorks2014 e criei uma versão ampliada da tabela SalesOrderDetail com base no script disponível em meu blog. A tabela SalesOrderDetailEnlarged foi ampliada para 2 GB de tamanho para que as operações UPDATE STATISTICS WITH FULLSCAN pudessem ser executadas em diferentes estatísticas na tabela simultaneamente. Em seguida, usei sp_whoisactive para examinar os bloqueios mantidos por ambas as sessões.

Comportamento sem TF 7471


O comportamento padrão do SQL Server requer um bloqueio exclusivo (X) no recurso OBJECT.UPDSTATS para a tabela sempre que um comando UPDATE STATISTICS é executado em uma tabela. Você pode ver isso na saída sp_whoisactive para duas execuções simultâneas de UPDATE STATISTICS WITH FULLSCAN na tabela Sales.SalesOrderDetailEnlarged, usando nomes de índice diferentes para a atualização das estatísticas. Isso resulta no bloqueio da segunda execução de UPDATE STATISTICS até que a primeira execução seja concluída.
ATUALIZAR ESTATÍSTICAS [Sales].[SalesOrderDetailEnlarged] ([PK_SalesOrderDetailEnlarged_SalesOrderID_SalesOrderDetailID]) COM FULLSCAN;
                                                
ATUALIZAR ESTATÍSTICAS [Vendas].[SalesOrderDetailEnlarged] ([IX_SalesOrderDetailEnlarged_ProductID]) COM FULLSCAN;
                                        

A granularidade do recurso de bloqueio em OBJECT.UPDSTATS impede atualizações simultâneas de várias estatísticas na mesma tabela. Os aprimoramentos de hardware nos últimos anos realmente mudaram os possíveis gargalos comuns às implementações do SQL Server e, assim como foram feitas alterações no DBCC CHECKDB para torná-lo mais rápido, alterando o comportamento de bloqueio de UPDATE STATISTICS para permitir atualizações simultâneas de estatísticas no a mesma tabela pode reduzir significativamente as janelas de manutenção para VLDBs, especialmente onde há capacidade suficiente de CPU e subsistema de E/S para permitir atualizações simultâneas sem afetar as experiências do usuário final.

Comportamento com TF 7471


O comportamento de bloqueio com o sinalizador de rastreamento 7471 habilitado muda de exigir um bloqueio exclusivo (X) no recurso OBJECT.UPDSTATS para exigir um bloqueio de atualização (U) no recurso METADATA.STATS para a estatística específica que está sendo atualizada, o que permite execuções simultâneas de UPDATE STATISTICS na mesma tabela. A saída de sp_whoisactive para os mesmos comandos UPDATE STATISTICS WITH FULLCAN com o sinalizador de rastreamento ativado é mostrada abaixo:
ATUALIZAR ESTATÍSTICAS [Sales].[SalesOrderDetailEnlarged] ([PK_SalesOrderDetailEnlarged_SalesOrderID_SalesOrderDetailID]) COM FULLSCAN;
                                        
ATUALIZAR ESTATÍSTICAS [Vendas].[SalesOrderDetailEnlarged] ([IX_SalesOrderDetailEnlarged_ProductID]) COM FULLSCAN;
                                                     
Para VLDBs, que estão se tornando muito mais comuns, isso pode fazer uma grande diferença no tempo necessário para realizar atualizações de estatísticas em um servidor.

Recentemente escrevi sobre uma solução de manutenção paralela para SQL Server usando scripts de manutenção do Service Broker e Ola Hallengren como forma de otimizar as tarefas de manutenção noturna e reduzir o tempo necessário para reconstruir índices e atualizar estatísticas em servidores que têm bastante CPU e capacidade de E/S acessível. Como parte dessa solução, forcei uma ordem de tarefas de enfileiramento para o Service Broker para tentar evitar execuções simultâneas na mesma tabela para tarefas de reconstrução/reorganização de índice e UPDATE STATISTICS. O objetivo disso era manter os trabalhadores o mais ocupados possível até o final das tarefas de manutenção, onde as coisas seriam serializadas em execução com base no bloqueio de tarefas simultâneas.

Fiz algumas modificações no processamento nesse post para testar apenas os efeitos desse sinalizador de rastreamento apenas com atualizações de estatísticas simultâneas, e os resultados estão abaixo.

Teste de desempenho de atualização de estatísticas simultâneas


Para testar o desempenho de apenas atualizar estatísticas em paralelo usando a configuração do Service Broker, comecei criando uma estatística de coluna em cada coluna no banco de dados AdventureWorks2014 usando o script a seguir para gerar os comandos DDL a serem executados.
USE [AdventureWorks2014]GO SELECT *, 'DROP STATISTICS ' + QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME) + '.' + QUOTENAME(c.TABLE_NAME + '_' + c.COLUMN_NAME) + ';GOCREATE STATISTICS ' +QUOTENAME(c.TABLE_NAME + '_' + c.COLUMN_NAME) + 'ON ' + QUOTENAME(c.TABLE_SCHEMA) + '. ' + QUOTENAME(c.TABLE_NAME) + ' (' +QUOTENAME(c.COLUMN_NAME) + ');' + 'IR' DE INFORMATION_SCHEMA.COLUMNS AS cINNER JOIN INFORMATION_SCHEMA.TABLES AS t ON c.TABLE_CATALOG =t.TABLE_CATALOG AND c.TABLE_SCHEMA =t.TABLE_SCHEMA AND c.TABLE_NAME =t.TABLE_NAMEWHERE t.TABLE_TYPE ='BASE TABLE' AND c .DATA_TYPE <> N'xml';

Isso não é algo que você normalmente gostaria de fazer, mas me fornece muitas estatísticas para testes paralelos do impacto do sinalizador de rastreamento na atualização de estatísticas simultaneamente. Em vez de randomizar a ordem em que enfileirar as tarefas para o Service Broker, apenas enfileirar as tarefas como elas existem na tabela CommandLog com base no ID da tabela, simplesmente incrementando o ID em um até que todos os comandos tenham sido enfileirados Para processamento.
USE [mestre]; -- Limpa o Log de Comandos TRUNCATE TABLE [master].[dbo].[CommandLog]; DECLARE @MaxID INT;SELECT @MaxID =MAX(ID) FROM master.dbo.CommandLog; SELECT @MaxID =ISNULL(@MaxID, 1) ---- Carregar novas tarefas no comando LogEXEC master.dbo.IndexOptimize @Databases =N'AdventureWorks2014', @FragmentationLow =NULL, @FragmentationMedium =NULL, @FragmentationHigh =NULL, @UpdateStatistics ='ALL', @StatisticsSample =100, @LogToTable ='Y', @Execute ='N'; DECLARE @NewMaxID INTSELECT @NewMaxID =MAX(ID) FROM master.dbo.CommandLog; USE msdb; DECLARE @CurrentID INT =@MaxIDWHILE (@CurrentID <=@NewMaxID)BEGIN -- Inicia uma conversa e envia uma mensagem de solicitação DECLARE @conversation_handle UNIQUEIDENTIFIER; DECLARE @message_body XML; COMEÇAR A TRANSAÇÃO; BEGIN DIALOG @conversation_handle DO SERVIÇO [OlaHallengrenMaintenanceTaskService] PARA O SERVIÇO N'OlaHallengrenMaintenanceTaskService' NO CONTRATO [OlaHallengrenMaintenanceTaskContract] COM ENCRIPTAÇÃO =OFF; SELECT @message_body =N''+CAST(@CurrentID AS NVARCHAR)+N''; ENVIAR NA CONVERSA @conversation_handle TIPO DE MENSAGEM [OlaHallengrenMaintenanceTaskMessage] (@message_body); COMPROMETA A TRANSAÇÃO; SET @CurrentID =@CurrentID + 1;END WHILE EXISTS (SELECT 1 FROM OlaHallengrenMaintenanceTaskQueue WITH(NOLOCK))BEGIN WAITFOR DELAY '00:00:01.000'END WAITFOR DELAY '00:00:06.000' SELECT DATEDIFF(ms, MIN(StartTime ), MAX(EndTime)) FROM master.dbo.CommandLog;GO 10

Em seguida, esperei a conclusão de todas as tarefas, medi o delta no horário de início e término das execuções de tarefas e fiz a média de dez testes para determinar as melhorias apenas para atualizar estatísticas simultaneamente usando a amostragem padrão e as atualizações de verificação completa.



Os resultados do teste mostram que, mesmo com o bloqueio que ocorre sob o comportamento padrão sem o sinalizador de rastreamento, as atualizações de amostra de estatísticas são executadas 6% mais rápido e as atualizações de verificação completa são executadas 16% mais rápido com cinco threads processando as tarefas enfileiradas para o Service Broker. Com o sinalizador de rastreamento 7471 habilitado, as mesmas atualizações de amostra de estatísticas são executadas 38% mais rápido e as atualizações de varredura completa são executadas 45% mais rápido com cinco threads processando as tarefas enfileiradas para o Service Broker.

Potenciais desafios com TF 7471


Por mais atraentes que sejam os resultados do teste, nada neste mundo é gratuito e, em meus testes iniciais, encontrei alguns problemas com o tamanho da VM que eu estava usando no meu laptop que criava problemas de carga de trabalho.

Originalmente, eu estava testando a manutenção paralela usando uma VM de 4 vCPU com 4 GB de RAM que configurei especificamente para essa finalidade. À medida que comecei a aumentar o número de MAX_QUEUE_READERS para o procedimento de ativação no Service Broker, comecei a encontrar problemas com as esperas RESOURCE_SEMAPHORE quando o sinalizador de rastreamento estava habilitado, permitindo atualizações paralelas de estatísticas nas tabelas ampliadas no meu banco de dados AdventureWorks2014 devido aos requisitos de concessão de memória para cada um dos comandos UPDATE STATISTICS que estavam em execução. Isso foi aliviado alterando a configuração da VM para 16 GB de RAM, mas isso é algo a ser monitorado e observado ao executar tarefas paralelas em tabelas maiores, para incluir manutenção de índice, pois a falta de concessão de memória também afetará as solicitações do usuário final que podem estar tentando executar e precisa de uma concessão de memória maior também.

A equipe do produto também escreveu sobre esse sinalizador de rastreamento e em seu post eles alertam que cenários de impasse podem ocorrer durante a atualização simultânea de estatísticas enquanto as estatísticas também estão sendo criadas. Isso não é algo que eu tenha encontrado durante meus testes, mas é definitivamente algo para estar ciente (Kendra Little também avisa sobre isso). Como resultado disso, sua recomendação é que esse sinalizador de rastreamento seja habilitado apenas durante a execução da tarefa de manutenção paralela e, em seguida, deve ser desabilitado para períodos normais de carga de trabalho.

Aproveitar!