Baixe o app para aproveitar ainda mais
Prévia do material em texto
Administração de Banco de Dados II Aula 10: Automações de tarefas administrativas no SQL Server Apresentação A décima e última aula da disciplina Administração de Bancos de Dados II revisita as aulas anteriores para implementar as principais tarefas do dia a dia do administrador do SQL Server, como automações no SQL Server Agent. Ao �nal da aula, você será capaz de planejar, implementar e agendar tarefas administrativas que sejam executadas regularmente, auxiliando na monitoração e na administração das suas instâncias SQL Server. Objetivos Identi�car as principais tarefas administrativas para automação com o SQL Server Agent; Empregar automações para Administração de Bancos de Dados, Segurança e Auditoria, Gerenciamento de Processos, Transações e Bloqueios por meio do SQL Server Agent; Empregar automações para Tuning, para desempenho máximo contínuo nas instâncias SQL Server. Automações no SQL Server Chegamos à última aula com uma bagagem repleta de ferramentas. Sabemos como implantar nossos bancos de dados de acordo com as necessidades e as expectativas dos usuários; monitorar as cargas de trabalho submetidas às instâncias SQL Server; garantir cópias de segurança dos bancos de dados; e, gerenciar os processos, as transações e os bloqueios, entre outras tantas tarefas que aprendemos durante a disciplina. Mas dá para fazer tanta coisa ao mesmo tempo? Sem dúvida, o dia a dia de um Database Administrator (DBA) passa bem rápido. Mesmo com um bom planejamento das tarefas, muitas vezes não há tempo para realizar todas as veri�cações necessárias. O ideal é criar automações para executar regularmente as checagens e as tarefas repetitivas. Dica Toda vez que você realizar uma mesma tarefa repetidamente, é hora de automatizá-la. No SQL Server, a ferramenta para implementar automações é o SQL Server Agent. Tarefas repetitivas, como realização de backups e checklists diários, muitas vezes se comportam diferentemente do esperado. Nessa hora, o DBA deve ser avisado da anormalidade a ser tratada. É preciso construir uma solução que seja capaz não só de realizar as repetições mas também de distinguir entre um comportamento normal de um comportamento anormal. Antes, porém, de começar a construir nossos jobs, prepararemos alguns recursos básicos: um banco de dados, uma caixa postal, uma pasta para scripts e uma pasta para outputs dos jobs. Um banco de dados auxiliar para a execução dos trabalhos é importante porque muitas vezes você precisará armazenar stored procedures e tabelas para os dados gerados pelos jobs. É o banco de dados do DBA. Atenção O principal objetivo da utilização de ferramentas de automação é avisá-lo dos comportamentos observados que estão fora do padrão. Para isso, crie uma caixa postal para receber e-mails. A ideia é utilizar essa conta somente para e-mails que realmente demandam atenção do DBA. Além das stored procedures a serem armazenadas no banco de dados dos DBAs, você precisará construir um script Powershell ou Bash e chamá-los a partir do SQL Server Agent. Para isso, tenha uma pasta dedicada exclusivamente ao armazenamento dos scripts que serão executados pela conta do Agent. Você precisará conceder as permissões adequadas à credencial do Agent, de�nida durante a instalação do SQL Server. Por último, em muitos trabalhos, você precisará armazenar o output fora do SQL Server para utilizar ferramentas do sistema operacional sobre esses dados. Faz sentido, então, ter uma pasta específica para o Agent salvar os outputs quando necessário. SQL Server Agent A ferramenta do SQL Server para construção e agendamento de trabalhos é o SQL Server Agent. Um job do Agent é composto por steps (etapas) para os quais o administrador determina o que vai ser executado. Podem ser executados não somente scripts SQL Server mas também scripts Powershell e utilitários do sistema operacional, entre outros. No SQL Server Management Studio, você pode acessar o SQL Server Agent a partir do menu da instância. Ao clicar com o botão direito sobre a opção, você pode escolher Novo >> Trabalho. Você deve nomear o job e fornecer a categoria e a descrição dele. Se precisar desabilitar o trabalho, a qualquer momento, basta desmarcar a caixa Habilitado. Entre as opções à esquerda, estão as Etapas. É por meio dela que vamos de�nir todos os passos do trabalho. Para cada passo, você deve especi�car qual o tipo de instrução. No exemplo, foi de�nido que o passo Faz Backup é um script escrito em T-SQL cujo conteúdo está informado na caixa Comando. Para cada passo, você também deve informar, na aba Avançado, o que deve acontecer caso o passo seja executado com sucesso e o que deve acontecer caso o passo falhe. Por padrão, um passo executado com sucesso avança para o próximo passo, e um passo com falha na execução encerra o trabalho. Você pode ajustar esses comportamentos de acordo com a necessidade. Por exemplo, você pode, após a execução correta de determinado passo, avançar para o último passo do job. Ou ainda, em caso de falha de um passo, desviar a execução do trabalho para a execução de um passo que registre o erro em um sistema de controle de jobs. Em seguida, você deve de�nir os agendamentos. No exemplo, está sendo de�nido um agendamento que ocorre diariamente às 22 horas, sem prazo de término. Portanto, todos os dias às 22 horas serão executados os passos de�nidos. É possível con�gurar alertas e noti�cações para alimentar um sistema de monitoração ou mesmo enviar um e-mail. Veja na imagem a seguir. Para con�gurar um e-mail e receber noti�cações em uma caixa postal, é preciso con�gurar um operador no SQL Server Agent. Saiba mais Veja um passo a passo completo para a con�guração de um operador no SQL Server Agent em How to setup SQL Server alerts and email operator noti�cations. Para mais detalhes sobre o próprio Agent, visite SQL Server Agent. Administração de bancos de dados Começaremos a preparar nossos jobs pela seção de Administração de Bancos de Dados. Uma tarefa imprescindível para todo DBA é garantir a execução e a integridade do backup dos seus bancos de dados. Que tal agendar a execução periódica desses backups, tanto dos arquivos de dados quanto dos arquivos de log de transações? Além disso, que tal promover testes automáticos de restauração desses backups para checar sua integridade? Backup javascript:void(0); javascript:void(0); Os primeiros jobs que você deve con�gurar em suas instâncias, logo que cria um database, são aqueles relacionados ao backup do banco de dados e do log de transações. Conforme vimos na aula de Administração de Bancos de Dados, um backup do banco de dados pode ser disparado pelo comando a seguir. BACKUP DATABASE CRM TO DISK = 'H:\MSSQL.1\MSSQL\Backup\CRM.BAK' WITH INIT Dependendo da sua estratégia de backup, você pode con�gurar os backups diferenciais com a regularidade necessária. É importante também con�gurar o backup do log de transações, o que pode ser feito pelo comando a seguir. BACKUP LOG CRM TO DISK = 'H:\MSSQL.1\MSSQL\Backup\CRM_Log.BAK' WITH INIT Então, crie dois jobs para cada banco de dados: Um para o backup do banco, outro para o backup do log. Você não deve se esquecer de incluir o passo de erro para enviar um e-mail de alerta sobre o backup que deixou de ser realizado, o que deve provocar uma reação imediata no time de DBAs. Atenção Um ponto de atenção nos jobs de exemplo é que os backups estão sendo realizados para o mesmo arquivo em disco, logo, os arquivos são sobrepostos a cada execução. É preciso garantir que a ferramenta de backup corporativa realize a cópia desses arquivos na mesma regularidade que os trabalhos do SQL Server, ou utilize alguma técnica para nomear os arquivos de acordo com a data e hora. Veja um exemplo: DECLARE @nome_arquivo varchar(300) SELECT @nome_arquivo = (SELECT 'C:\Temp\CRM_' + convert(varchar(500),GetDate(),112) + '.bak') BACKUP DATABASE CRM TO DISK = @nome_Arquivo WITH INIT, COPY_ONLY Com esse passo, você consegue gerar um arquivo para cada data nomeando-o como CRM_20200706.BAK,por exemplo. Para incluir o horário de execução do backup, muito útil quando você tiver a execução do mesmo job várias vezes ao dia, utilize o formato 120, conforme a seguir. SELECT @nome_arquivo = 'C:\Temp\CRM_' + REPLACE(CONVERT(nvarchar(20),GetDate(),120),':','-') + '.BAK' No comando apresentado, o nome do arquivo gerado é CRM_2020-07-06 20-16-07.BAK. Testes de restore Tão importante quanto fazer os backups é testá-los. Um job para teste de restauração de banco de dados pode selecionar um ou mais backups e restaurá-los em bancos temporários de uma instância especi�camente preparada para esse �m. Prepare o trabalho de forma que uma noti�cação seja enviada ou um alerta seja emitido caso o comando SQL disparado não seja executado com sucesso. Você pode começar executando um RESTORE FILELISTONLY ou um RESTORE HEADERONLY. RESTORE FILELISTONLY FROM DISK='C:\Temp\CRM.bak' Para ir mais além, seu job pode ter dois passos, a saber, um para restaurar o database com um nome TESTE_RESTAURACAO, por exemplo, e outro para rodar uma veri�cação de integridade lógica e física em todos os objetos do banco de dados. Step 1: RESTORE DATABASE TESTE_RESTAURACAO FROM DISK='C:\Temp\CRM.bak' WITH STATS=5 Step 2: DBCC CHECKDB (‘TESTE_RESTAURACAO’); Note que sua instância deve conter as mesmas pastas dos arquivos de dados e log de transações, caso contrário você terá um erro de caminho não encontrado no sistema operacional. Se for necessário, você pode utilizar a cláusula WITH MOVE para alterar os caminhos dos arquivos. O output de um DBCC pode ser bem grande. O ideal é tomá-lo como entrada para um passo que execute uma pesquisa no output e só envie a noti�cação caso haja erros. Uma alternativa clássica para tratar as saídas de passos intermediários é armazená-las em arquivos do sistema operacional e realizar pesquisas sobre eles, utilizando para isso algum utilitário do próprio sistema operacional, como grep ou awk. No caso em estudo, você pode extrair a linha que contém o total de erros de alocação e consistência do banco de dados, como a mostrada a seguir. CHECKDB found 0 allocation errors and 0 consistency errors in database 'CRM'. Atenção Se você procurar por 0 allocation erros e 0 consistency erros e não encontrar as duas, há algo errado com seu backup e, possivelmente, com o banco de dados original. Volumes de bancos de dados Existem respostas que todo DBA deve ter na ponta da língua. Uma delas é Qual é o volume atual dos seus bancos de dados? Para ter esse tipo de informação sempre à mão, vamos criar um job no Agent que será executado diariamente e registrará, para cada banco de dados da instância, o volume de dados e o volume de log. Assim, você poderá consultá-lo sempre que quiser, ou ainda mostrá-los em um painel de monitoração. No código a seguir, criamos uma tabela temporária para armazenar os dados e utilizamos sp_msforeachdb para inserir nessa tabela o volume do arquivo de dados (type=0) e o volume do arquivo de log (type=1) de cada banco de dados da instância. if object_id('tempdb..#volume_bancos') is not null drop table #volume_bancos CREATE TABLE #volume_bancos ( Data datetime, Banco sysname, Volume_Dados decimal(13,2), Volume_Log decimal(13,2) ) EXEC sp_msforeachdb 'USE [?]; INSERT INTO #volume_bancos SELECT GETDATE() Data, DB_NAME() AS Banco, DADOS.Volume_Dados AS Volume_Dados, LOG.Volume_Log Volume_Log FROM ( SELECT SUM(CAST((f.size/128.0) AS DECIMAL(13,2))) AS Volume_Dados FROM sys.database_files AS f WITH (NOLOCK) where type = 0) AS DADOS CROSS JOIN ( SELECT SUM(CAST((f.size/128.0) AS DECIMAL(13,2))) AS Volume_Log FROM sys.database_files AS f WITH (NOLOCK) where type = 1) AS LOG ' SELECT * FROM #volume_bancos; GO Dica Note que estamos utilizando uma tabela temporária, mas você pode persistir esses dados em uma tabela não temporária, de preferência armazenado em um banco de dados de controle. Para isso, você pode ter algo do tipo INSERT INTO DBA..volume_bancos. Outro ponto interessante é que estamos considerando o volume ocupado pelos arquivos, em vez do volume utilizado efetivamente pelos dados. É uma decisão que cabe a você. Se quiser considerar o volume utilizado, basta recuperar a propriedade SPACEUSED em uma construção como a mostrada a seguir. SUM(CAST(CAST(FILEPROPERTY(f.name, ''SpaceUsed'') AS int)/128.0 AS DECIMAL(13,2))) AS Volume_Usado Atividade 1. Como você faria para ter uma única tabela de controle em uma instância central, a qual pudesse armazenar os volumes de todos os bancos de dados de todas as instâncias SQL Server do seu ambiente? Que recursos vistos durante a disciplina poderiam ser utilizados para compor essa solução? Segurança e auditoria Há muitos relatórios a respeito de Segurança e Auditoria que podem ser agendados pelo Agent. Vimos alguns deles na aula correspondente. Do ponto de vista do DBA, o ideal é checar regularmente em busca de falhas de segurança que possam comprometer os bancos de dados. Além disso, é importante veri�car itens frequentes de auditoria e cuidar para não ser pego de surpresa. Falhas de login Um alerta frequente para DBAs ocorre quando há sucessivas falhas de login de um usuário. É preciso checar o que está acontecendo, pois esse tipo de comportamento pode signi�car uma tentativa de invasão. Falhas de login são registradas no log de erros do SQL Server. É importante veri�car se essa captura está habilitada, por meio da opção Segurança das Propriedades da instância, conforme a imagem a seguir. Deixe marcado Failed Logins Only para capturar somente as falhas de login. Os registros dessas falhas são gravados no error log do SQL Server e você pode utilizar a procedure xp_readerrorlog para ler esses registros. Veja um exemplo a seguir. EXEC sp_readerrorlog 0, 1, 'Login failed' O comando mostrado retornará todos os registros de falha de login, o que deve ser enviado para análise. Validação de logins A validação é fundamental para checar se há algum login do SQL Server mapeado para um usuário ou grupo do Windows que não existe. Como vimos em aulas anteriores, você pode carregar o output de uma procedure em uma tabela criada por você. Veja um exemplo de passo do job. INSERT INTO DBA..sec_validatelogins EXEC sp_validatelogins; Se a tabela auxiliar não estiver vazia, é porque existem logins não válidos que devem ser checados e eventualmente removidos da instância. Administradores das instâncias É importante checar regularmente quem são os membros das roles �xas das instâncias SQL Server, especialmente os sysadmins. INSERT INTO DBA..sec_helpsrvrolemember EXEC sp_helpsrvrolemember; Estabeleça seus critérios de pesquisa segundo os padrões de suas instâncias. Diferentemente do resultado anterior, essa tabela conterá os administradores da instância. O job deverá realizar uma pesquisa nas linhas da tabela, procurando por alguma ocorrência que esteja fora do padrão. Privilégios em bancos de dados Da mesma forma, veri�car os membros das roles �xas dos bancos de dados da instância também é uma boa prática para garantir a segurança tanto dos bancos de dados, quanto dos dados propriamente ditos. Você não vai querer usuários indevidos nos grupos db_datawriter de seus bancos de dados, certo? Podemos esquematizar o job con�gurando três passos, a saber, um para drop da tabela auxiliar, um para create e outro para passear pelos bancos de dados da instância e recuperar os membros das roles �xas dos bancos de dados da instância. Step 1: DROP TABLE DBA..sec_databaserolemember; Step 2: CREATE TABLE DBA..sec_databaserolemember (DatabaseName sysname, DatabaseRoleName sysname, DatabaseUserName sysname) Step 3: EXEC sp_msforeachdb ' USE [?] INSERT INTO DBA..sec_databaserolemember SELECT DB_NAME() AS DatabaseName, DP1.name AS DatabaseRoleName, isnull (DP2.name, ''No members'') AS DatabaseUserName FROM sys.database_role_members AS DRM RIGHT OUTER JOIN sys.database_principals AS DP1 ON DRM.role_principal_id = DP1.principal_id LEFT OUTER JOIN sys.database_principalsAS DP2 ON DRM.member_principal_id = DP2.principal_id WHERE DP1.type = ''R'' ORDER BY DP1.name; Mais uma vez, você deve estabelecer seus critérios de pesquisa segundo os padrões de suas instâncias. Podemos concluir, adicionalmente, que um padrão para nomes de usuários é fundamental para uma boa administração das instâncias SQL Server. Exemplo As checagens para validação de logins e concessão de privilégios, por exemplo, são baseadas no padrão de�nido para suas instâncias. Monitoração e gerenciamento de processos Na aula de Monitoração e Gerenciamento de Processos, aprendemos como funcionam as �las de execução e como se dá a transição dos estados de um processo. Vimos como monitorar esses estados e os tempos de espera associados, construindo técnicas para avaliar quando determinados comportamentos começam a impactar o desempenho geral da instância e quando é hora de atuar. Vamos agora fazer o SQL Server Agent nos avisar quando esses comportamentos começarem a acontecer. Atenção Não adianta construir relatórios imensos que ninguém vai ler. Trata-se de construir monitorações dinâmicas e disparar noti�cações somente quando houver necessidade de atuação. Volume de tarefas em execução x Volume de tarefas em espera Utilizamos, na aula de Monitoração e Gerenciamento de Processos, a construção a seguir para recuperar a quantidade de tarefas por scheduler e estado. SELECT [ot].[scheduler_id], [task_state], COUNT (*) AS [task_count] FROM sys.dm_os_tasks AS [ot] INNER JOIN sys.dm_exec_requests AS [er] ON [ot].[session_id] = [er].[session_id] INNER JOIN sys.dm_exec_sessions AS [es] ON [er].[session_id] = [es].[session_id] WHERE [es].[is_user_process] = 1 GROUP BY [ot].[scheduler_id], [task_state] ORDER BY [task_state], [ot].[scheduler_id]; GO Uma discussão importante no escopo do gerenciamento de processos está relacionada ao volume de tarefas que estão em execução na instância e ao volume de tarefas que estão suspensas, aguardando algum tipo de recurso. Queremos maximizar o número de tarefas RUNNING ou RUNNABLE, minimizando o número de tarefas que estão no estado SUSPENDED. Naturalmente, não há um número previamente estipulado que você deve perseguir, pois as instâncias, bancos de dados e cargas de trabalho têm suas próprias características e recursos disponíveis. O que se propõe é que você acompanhe os números relacionados às suas instâncias com o objetivo de criar faixas de referência para o que é normal. Assim, quando as taxas estiverem fora desse normal, uma noti�cação deve ser disparada. Comece criando um job que armazene, em intervalos curtos de tempo, os contadores por estado em uma tabela auxiliar. Essa tabela deve conter uma coluna Normal com valor padrão 1. Acompanhe os números. Quando houver uma degradação de desempenho geral na instância, veri�que os últimos números armazenados. Atualize a coluna Normal com o valor 0 para as observações do período de degradação. Repetindo o procedimento, você constrói uma base de observações da instância que, mais tarde, servirá de insumo para a de�nição das faixas de referência. Essa prática é comum e você pode utilizá-la não só nessa automação, mas em todas aquelas para as quais seja necessário construir uma referência. Comece sempre conhecendo suas instâncias e bancos de dados para, somente depois que estiver seguro quanto às faixas, implantar um job que emita um alerta quando observar um comportamento anormal. A construção a seguir agrupa por estado: CREATE TABLE DBA..taskstate (datahora datetime, estado varchar(20), contador int) INSERT INTO DBA..taskstate SELECT GETDATE() AS datahora, [task_state], COUNT(*) AS [task_count] FROM sys.dm_os_tasks AS [ot] INNER JOIN sys.dm_exec_requests AS [er] ON [ot].[session_id] = [er].[session_id] INNER JOIN sys.dm_exec_sessions AS [es] ON [er].[session_id] = [es].[session_id] WHERE [es].[is_user_process] = 1 GROUP BY [task_state] ORDER BY [task_state] GO Veja um exemplo de saída do SELECT para uma instância que suporta uma carga de trabalho com poucas transações. Há 7 tarefas suspensas em um total de 20, em uma relação frequentemente normal. datahora task_state task_count 2020-07-06 11:31:43.413 RUNNABLE 2 2020-07-06 11:31:43.413 RUNNING 11 2020-07-06 11: 31:43.413 SUSPENDED 7 Veja outro exemplo de saída do SELECT, desta vez para uma instância de Data Warehouse que suporta um volume maior de transações simultâneas. Há 337 tarefas suspensas em um total de 546, com cerca de 61% em SUSPENDED e quase ¼ das transações em RUNNABLE, algo frequentemente apontado como anormal. datahora task_state task_count 2020-07-06 11:31:43.413 RUNNABLE 128 2020-07-06 11:31:43.413 RUNNING 81 2020-07-06 11: 31:43.413 SUSPENDED 337 Atenção Mais uma vez, somente por meio de observações regulares em suas instâncias é que você vai chegar a uma conclusão para estabelecer uma faixa normal de volume de tarefas por estado. Tarefas em espera de usuários Outra ferramenta importante no universo do gerenciamento de processos é a visão dinâmica de tarefas em espera waiting tasks. Essa visão fornece dados de tempo de espera associados ao tipo de espera, como CXPACKET e PAGEIOLATCH. Veja a seguinte construção: SELECT [owt].[session_id], [owt].[exec_context_id], [owt].[wait_duration_ms], [owt].[wait_type], [owt].[blocking_session_id], [owt].[resource_description], [es].[program_name], [est].[text], [est].[dbid], [eqp].[query_plan], [es].[cpu_time], [es].[memory_usage] FROM sys.dm_os_waiting_tasks [owt] INNER JOIN sys.dm_exec_sessions [es] ON [owt].[session_id] = [es].[session_id] INNER JOIN sys.dm_exec_requests [er] ON [es].[session_id] = [er].[session_id] OUTER APPLY sys.dm_exec_sql_text ([er].[sql_handle]) [est] OUTER APPLY sys.dm_exec_query_plan ([er].[plan_handle]) [eqp] WHERE [es].[is_user_process] = 1 ORDER BY [owt].[session_id], [owt].[exec_context_id] GO A ideia de um trabalho de monitoramento de tempos de espera é avisar quando esses tempos �carem muito altos. A análise para a de�nição de faixas de tempos deve ser realizada por tipo de espera; por esse motivo, a construção a seguir faz o agrupamento por wait_type. SELECT [owt].[wait_type], SUM([owt].[wait_duration_ms]) AS total_time FROM sys.dm_os_waiting_tasks [owt] INNER JOIN sys.dm_exec_sessions [es] ON [owt].[session_id] = [es].[session_id] INNER JOIN sys.dm_exec_requests [er] ON [es].[session_id] = [er].[session_id] OUTER APPLY sys.dm_exec_sql_text ([er].[sql_handle]) [est] OUTER APPLY sys.dm_exec_query_plan ([er].[plan_handle]) [eqp] WHERE [es].[is_user_process] = 1 GROUP BY [owt].[wait_type] ORDER BY [owt].[wait_type] GO Dica Use a mesma estratégia. Crie uma tabela auxiliar no banco DBA e registre regularmente os tempos por data e hora e tipo de bloqueio. Entenda quais são os tempos razoáveis para CXPACKET, PAGEIOLATCH e todos os tipos LCK_* correspondentes aos bloqueios. Gerenciamento de transações e bloqueios Tempos de bloqueios podem ser muito grandes. Veja um resultado possível da construção apresentada anteriormente: wait_type total_time LCK_M_IX 11917 LCK_M_S 20593 LCK_M_X 707803343 Comentário O tempo de espera por um bloqueio exclusivo é muito maior, mas isso é absolutamente comum. Tempos de espera por bloqueios exclusivos tendem a ser muito maiores que tempos de espera por bloqueios compartilhados, principalmente em bancos de dados transacionais, nos quais há muitas atualizações. Com um comportamento diferente, em bancos de dados analíticos há muito mais consultas e, portanto, não há muita espera por bloqueio exclusivo. Veja um exemplo retirado de uma instância desse tipo: wait_type total_time ASYNC_IO_COMPLETION 11083 BACKUPBUFFER 3561 BACKUPIO 37255 CXPACKET 14484632 IO_COMPLETION 4769 SP_SERVER_DIAGNOSTICS_SLEEP 910 TRACEWRITE 1065 Os maiores tempos estão em esperas do tipo CXPACKET, normalmente encontradas na execução de threads paralelas, como vimos na aula de Gerenciamento de Transações e Bloqueios. É fundamental acostumar-se com os temposde bloqueio das suas instâncias. Eles tendem a se repetir no dia a dia. Naturalmente, se o banco apresenta alguma característica de sazonalidade, então esses tempos vão variar, assim como o próprio volume de transações. Nesses casos, você vai construir duas ou mais faixas de referência e basear seus trabalhos nestas. Cadeia de bloqueios Tão importante quanto o monitoramento dos tempos de bloqueio é o monitoramento dos bloqueios propriamente ditos. Acompanhar o volume de bloqueios das suas instâncias para criar faixas de referências é uma primeira abordagem. Algo que pode ser muito interessante também é acompanhar a profundidade das cadeias de bloqueio. Você se lembra de que utilizamos um script clássico que representa gra�camente as cadeias de bloqueio? Para cada cadeia, é mostrada a cabeça, como no seguinte exemplo: HEAD - 60 BEGIN TRANSACTION UPDATE CRM.Usuarios SET id_resp=4 WHERE id_usuario=4 |---------|------ 56 (@1 int,@2 tinyint)UPDATE [CRM].[Usuarios] set [id_resp] = @1 WHERE [id_usuario]=@2 |---------|-------|------ 61 (@1 int,@2 tinyint)UPDATE [CRM].[Usuarios] set [id_resp] = @1 WHERE [id_usuario]=@2 |---------|-------|------ 65 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT * FROM CRM.Usuarios No exemplo, a cabeça da cadeia é a sessão 60 e a cadeia tem uma profundidade de 3, pois são três as sessões bloqueadas. A ideia é acompanhar as cadeias de bloqueio para determinar a profundidade média nas suas instâncias. Vejamos como fazê-lo. A primeira parte do script gera uma tabela temporária #T com a lista dos processos em execução e os bloqueios correspondentes. SET NOCOUNT ON GO SELECT SPID, BLOCKED, REPLACE (REPLACE (T.TEXT, CHAR(10), ' '), CHAR (13), ' ' ) AS BATCH INTO #T FROM sys.sysprocesses R CROSS APPLY sys.dm_exec_sql_text(R.SQL_HANDLE) T GO WITH BLOCKERS (SPID, BLOCKED, LEVEL, BATCH) AS ( SELECT SPID, BLOCKED, CAST (REPLICATE ('0', 4-LEN (CAST (SPID AS VARCHAR))) + CAST (SPID AS VARCHAR) AS VARCHAR (1000)) AS LEVEL, BATCH FROM #T R WHERE (BLOCKED = 0 OR BLOCKED = SPID) AND EXISTS (SELECT * FROM #T R2 WHERE R2.BLOCKED = R.SPID AND R2.BLOCKED <> R2.SPID) UNION ALL SELECT R.SPID, R.BLOCKED, CAST (BLOCKERS.LEVEL + RIGHT (CAST ((1000 + R.SPID) AS VARCHAR (100)), 4) AS VARCHAR (1000)) AS LEVEL, R.BATCH FROM #T AS R INNER JOIN BLOCKERS ON R.BLOCKED = BLOCKERS.SPID WHERE R.BLOCKED > 0 AND R.BLOCKED <> R.SPID ) SELECT SPID, COUNT(BLOCKED) AS Profundidade FROM BLOCKERS GROUP BY SPID ORDER BY SPID DROP TABLE #T GO A segunda parte gera a cadeia completa, incluindo os níveis (LEVEL) de cada sessão na cadeia. A terceira parte faz a contagem para determinar a profundidade. SPID Profundidade 344 1 349 4 Comentário É esperado que não haja longas cadeias de bloqueio em suas instâncias. Se elas estão acontecendo com frequência, em uma profundidade maior que a faixa de referência, então é melhor investigar para entender a causa raiz. É possível que uma reescrita das consultas resolva o problema. Lembre-se das técnicas e das boas práticas aprendidas na aula sobre Bloqueios. Tuning Atualização de estatísticas Boa parte dos problemas relacionados a desempenho em bancos de dados é oriundo de estatísticas desatualizadas. Como vimos na aula sobre Tuning, o otimizador do SGBD utiliza as cardinalidades e os histogramas constantes das estatísticas para selecionar os melhores operadores em planos de execução. Naturalmente, quanto mais se mantiverem atualizadas, maior a chance de termos planos de execução com melhor desempenho. É o que vamos fazer. O procedimento a seguir percorre todos os objetos do banco de dados corrente e prepara um comando UPDATE STATISTICS para cada tabela encontrada. SELECT o.NAME, sc.NAME, i.NAME, sp.last_updated, sp.rows, sp.rows_sampled, 'UPDATE STATISTICS [' + sc.NAME + '].[' + o.NAME + '] WITH FULLSCAN' AS [Comandos] FROM sys.objects AS o INNER JOIN sys.schemas sc ON (o.schema_id = sc.schema_id) INNER JOIN sys.indexes AS i ON (o.object_id = i.object_id) INNER JOIN sys.stats AS s ON (i.object_id = s.object_id) CROSS apply sys.dm_db_stats_properties(s.object_id, s.stats_id) AS sp WHERE sp.rows <> sp.rows_sampled AND o.type = 'U' AND i.is_unique = 1 AND s.stats_id = 1 Note que os objetos selecionados são aqueles para os quais o total de linhas é diferente do total de linhas utilizadas como amostra para a geração das estatísticas. Se forem iguais, não é necessária nova atualização das estatísticas. O resultado da execução do procedimento mostra os seguintes comandos: UPDATE STATISTICS [CRM].[Usuarios] WITH FULLSCAN UPDATE STATISTICS [CRM].[Usuarios_Documentos] WITH FULLSCAN UPDATE STATISTICS [CRM].[Usuarios_Historico] WITH FULLSCAN UPDATE STATISTICS [CRM].[Usuarios_Historico_Part] WITH FULLSCAN Com base nesse procedimento, podemos preparar um job que percorra todos os bancos de dados da instância por meio de sp_msforeachdb e, para cada banco de dados, gere um comando UPDATE STATISTICS para cada objeto do banco de dados, armazenando esse comando em uma tabela temporária. Ao término da busca em todos os bancos de dados, podemos executar os comandos armazenados na tabela temporária. Veja como podemos fazê-lo: EXEC sp_msforeachdb 'IF ''?'' NOT IN ('CRM'') AND databasepropertyex(''?'',''Updateability'') = ''READ_WRITE'' BEGIN USE [?] INSERT INTO #update_stats SELECT ''?'', o.NAME, sc.NAME, i.NAME, sp.last_updated, sp.rows, sp.rows_sampled, ''UPDATE STATISTICS [?].['' + sc.NAME + ''].['' + o.NAME + ''] WITH FULLSCAN'' AS [CMD] FROM sys.objects AS o INNER JOIN sys.schemas sc ON (o.schema_id = sc.schema_id) INNER JOIN sys.indexes AS i ON (o.object_id = i.object_id) INNER JOIN sys.stats AS s ON (i.object_id = s.object_id) CROSS apply sys.dm_db_stats_properties(s.object_id, s.stats_id) AS sp WHERE AND sp.rows <> sp.rows_sampled AND o.type = ''U'' AND i.is_unique = 1 AND s.stats_id = 1 END Trata-se do mesmo SELECT utilizado anteriormente, sendo que o resultado é inserido na tabela temporária #update_stats. Para executar esses comandos, podemos utilizar o seguinte cursor: DECLARE cur_stats CURSOR LOCAL FORWARD_ONLY FAST_FORWARD READ_ONLY FOR SELECT DatabaseName, CMD FROM #update_stats OPEN cur_stats FETCH NEXT FROM cur_stats INTO @DatabaseName, @cmd WHILE @@fetch_status = 0 BEGIN PRINT @cmd EXEC sp_executesql @cmd FETCH NEXT FROM cur_stats INTO @DatabaseName, @cmd END CLOSE cur_stats DEALLOCATE cur_stats O cursor percorre a tabela temporária e, para cada linha selecionada pelo FETCH, executa o comando correspondente em @cmd. O loop WHILE continua enquanto houver novas linhas (@@fetch_status=0). Note que estamos usando FULLSCAN na atualização das estatísticas. Nem sempre isso é possível, pois o tempo para atualizar as estatísticas percorrendo a tabela inteira pode ser proibitivo. Para esses casos, você utilizará abordagens alternativas, como selecionar algumas tabelas de acordo com rows_sampled, ou ainda utilizar a cláusula SAMPLE para considerar somente parte da tabela. Atenção Novamente, estatísticas desatualizadas são a fonte mais frequente de problemas de desempenho. Não é fácil encontrar janela para atualização FULLSCAN em tabelas muito grandes. Logo, a saída será utilizar amostras. Aí é que mora o perigo. Estatísticas atualizadas com SAMPLE são a segunda fonte mais frequente de problemas de desempenho. Lute bravamente para atualizar suas estatísticas com o maior número possível de amostras. Monitore constantemente. Invista seu tempo nisso. Índices não utilizados Por incrível que pareça, você frequentemente encontrará índices não utilizados ou pouco utilizados em bancos de dados. Se levarmos em consideração o custo de manutenção desses índices, principalmente nas cargas de tabelas grandes, é possível que você opte por destruir índices. A query a seguir mostra o total de varreduras (scans), buscas (seeks), pesquisa (lookups) e atualizações (updates). SELECT OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], I.[NAME] AS [INDEX NAME], USER_SEEKS,USER_SCANS, USER_LOOKUPS, USER_UPDATES FROM SYS.DM_DB_INDEX_USAGE_STATS AS S INNER JOIN SYS.INDEXES AS I ON I.[OBJECT_ID] = S.[OBJECT_ID] AND I.INDEX_ID = S.INDEX_ID WHERE OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 AND S.database_id = DB_ID() Se você observar valores zero, é sinal de que não estão sendo utilizados e podem ser removidos. Se você observar valores perto de zero, é sinal de que estão sendo utilizados, mas talvez seu custo de manutenção não se justi�que com pouco uso. Reconstrução de índices Como vimos na aula sobre Tuning, índices e índices parciais têm um papel fundamental no desempenho das consultas submetidas ao SGBD. O otimizador se baseia nas estatísticas das tabelas e nas visões indexadas para selecionar um ou outro índice. Para que toda a cadeia de otimização funcione adequadamente, é preciso manter os índices em bom estado para que eles atendam ao propósito de bene�ciar a execução das consultas. Mantê-los em bom estado signi�ca monitorar o armazenamento, detectar rapidamente quando houver sinais de fragmentação e automatizar a reorganização ou a recompilação do índice. Durante a vida útil de um índice, linhas vão sendo inseridas, atualizadas e removidas. Esta dinâmica provoca naturalmente uma desorganização das páginas que contêm os as linhas do índice, fazendo a sua ordenação lógica (a que é baseada na chave) começar a �car diferente da ordenação física das páginas do índice. Esse processo é conhecido como Fragmentação. Não queremos índices fragmentados porque ocorre aumento expressivo no volume de I/O e, muito provavelmente, nos tempos de espera do tipo PAGEIOLATCH, que corresponde às esperas por leituras de páginas do disco. Como, em um índice fragmentado, é necessário ler um número maior de páginas, há uma chance maior de contenção nessas páginas que cresce junto com o nível de fragmentação. A próxima consulta retorna, para cada par tabela/índice do banco de dados selecionado, o número de páginas e o percentual de fragmentação. USE CRM GO SELECT DB_NAME() As 'Banco', S.name as 'Esquema', T.name as 'Tabela', I.name as 'Indice', ISTAT.page_count AS [N Pag], ISTAT.avg_fragmentation_in_percent AS [Perc Frag] FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS ISTAT INNER JOIN sys.tables T on T.object_id = ISTAT.object_id INNER JOIN sys.schemas S on T.schema_id = S.schema_id INNER JOIN sys.indexes I ON I.object_id = ISTAT.object_id AND ISTAT.index_id = I.index_id WHERE ISTAT.database_id = DB_ID() and I.name is not null AND ISTAT.avg_fragmentation_in_percent > 0 ORDER BY ISTAT.avg_fragmentation_in_percent desc O resultado da execução da consulta no banco CRM mostra a seguinte lista: Banco Esquema Tabela Indice N Pag Perc Frag CRM CRM Usuarios_Historico ind_usuarios_historico_data 350 99,4285714285714 CRM CRM Usuarios PK__Usuarios__4E3E04ADE0DEE07B 9 11,1111111111111 CRM CRM Usuarios_Historico PK__Usuarios__4E3E04AD1063EF69 521 0,57581573896353 Veja que a maior parte dos índices do banco não apareceram na listagem porque possuem percentual de fragmentação igual a 0. O índice clustered da tabela Usuarios_Historico está muito pouco fragmentado e o índice clustered da tabela Usuarios já apresenta alguma fragmentação, entretanto, o índice non-clustered ind_usuarios_historico_data está muito fragmentado. Nesse caso, devemos atuar para reduzir a fragmentação e temos duas opções para isso: Reorganização e Recompilação. A reorganização consiste em movimentar páginas e linhas na organização interna do índice para reduzir a fragmentação. A recompilação reconstrói completamente o índice e pode ser feita online ou o�ine. No modo o�ine, a tabela �ca indisponível até que o processo termine. Segundo a Microsoft, em Resolver a fragmentação do índice reorganizando ou recompilando índices , você deve utilizar a referência a seguir, para determinar se o índice deve ser reorganizado ou recompilado. Valoravg_fragmentation_in_percent Instrução corretiva > 5% e < = 30% ALTER INDEX REORGANIZE > 30% ALTER INDEX REBUILD WITH (ONLINE = ON) 1 1 2 O job Agent que monitora a fragmentação pode usar uma tabela temporária para armazenar semanalmente, por exemplo, os níveis de fragmentação dos índices. Esse seria o primeiro passo. Em um segundo passo, pode montar um ou outro comando SQL para reorganizar ou recompilar o índice, dependendo do nível de fragmentação. Em nosso exemplo, vamos fazer um REORGANIZE no índice clusterizado da tabela Usuarios e um REBUILD no índice não clusterizado. javascript:void(0); ALTER INDEX PK__Usuarios__4E3E04ADE0DEE07B ON CRM.Usuarios REORGANIZE; ALTER INDEX ind_usuarios_historico_data ON CRM.Usuarios_Historico REBUILD WITH (ONLINE=ON); Após o término do processo, você pode checar novamente os índices de fragmentação. Veja o resultado: Banco Esquema Tabela Indice N Pag Perc Frag CRM CRM Usuarios PK__Usuarios__4E3E04ADE0DEE07B 9 11,111111111111 CRM CRM Usuarios_Historico ind_usuarios_historico_data 347 0,5763688760806 CRM CRM Usuarios_Historico PK__Usuarios__4E3E04AD1063EF69 521 0,5758157389635 Veja que não só o nível de fragmentação do índice não clusterizado diminuiu, como também diminuiu o número de páginas necessárias para armazenar o índice. Isso se deve ao fato de que, na reconstrução, uma maior concentração de linhas foi utilizada nas páginas e, portanto, menos páginas foram alocadas. Podemos observar também que não houve redução no nível de fragmentação do índice PK__Usuarios__4E3E04ADE0DEE07B. Isso pode acontecer em algumas situações, por exemplo, em estruturas muito pequenas. O índice clusterizado em questão possui 9 páginas e sua composição de páginas e linhas não permite uma desfragmentação maior. Saiba mais Para ver um passo a passo focado na resolução de problemas de fragmentação, acesse How to identify and resolve SQL Server Index Fragmentation. javascript:void(0); Conclusão Chegamos ao �nal da disciplina com a certeza de termos construído um bom ferramental para encarar a administração de instâncias SQL Server. Especialmente nesta aula, revisitamos os tópicos abordados durante todo o percurso e construímos automações para nos ajudar na tarefa desa�adora de prover bancos de dados SQL Server com disponibilidade, segurança, monitoração e desempenho adequados aos requisitos de negócio e às expectativas dos usuários. Automações são a convergência da experiência do DBA e da necessidade de executar tarefas repetitivas que fazem toda a diferença no seu dia a dia. É bastante comum ter centenas de jobs con�gurados no Agent. Vimos apenas alguns deles. Log Shipping, Replicações Transacionais e Mirroring são fortemente apoiados por trabalhos. Identi�que-os. Consulte regularmente seus históricos. Não hesite em investir tempo para construir a própria caixa de ferramentas. Existem muitos sites, muitos scripts, muitas técnicas, mas nem todas serão adequadas às suas instâncias, que terão características muito próprias de disponibilidade de recursos, aplicações, usuários e consultas. Portanto, construa você mesmo os seus arquivos.sql! Sinta-se em casa com suas ferramentas. DBAs são tentados a baixar scripts e ferramentas de sites especializados para resolver problemas. Não faça isso. Muito embora uma grande parte dos sites ofereçam ferramentas e�cientes e seguras, é importante que você entenda os códigos que serão executados nas suas instâncias. Certamente você vai querer fazer adequações. Seja você mesmo o DBA das suas instâncias SQL Server. Atividades 1. Entre os jobs a seguir, assinale os que podem ser implantados por um administrador por meio do SQL Server Agent. a) Monitoração de volumes de bancos de dados b) Reconstrução de índices não clusterizados c) Geração de cópias de segurança e realização de testes de restauração d) Todas as alternativas anteriores e) Nenhuma das alternativas anteriores 2. Assinale a alternativa INCORRETA a respeito de automações no SQL Server. a) É fundamental construir um job de verificação de falhas de login. Sucessivas falhaspodem indicar uma tentativa de invasão por força bruta e, nesse caso, é preciso investigar a origem dessas tentativas. b) Um job de monitoração de tempos de espera pode enviar uma notificação para a caixa postal dos DBAs informando, por exemplo, que há uma degradação nos tempos associados a operações de leitura de páginas do disco para memória. c) É possível criar um job no Agent para realizar os backups de todos os bancos de dados da instância e transferir os arquivos de backup para a nuvem. d) É possível criar um job para executar regularmente SHRINKFILE de todos os arquivos dos bancos de dados da instância, com o objetivo de manter os volumes alocados pelos arquivos próximos dos volumes realmente ocupados pelos dados. e) É fundamental construir um job para a monitoração das transações em execução na instância. Nos casos em que cadeias de bloqueio se formam, é possível identificar a cabeça do bloqueio e interromper a sessão, liberando todas as transações que voltam a executar imediatamente. 3. Assinale a(s) alternativa(s) INCORRETA(S) a respeito de jobs como ação de sintonia �na no SQL Server. a) A análise da fragmentação de índices é fundamental para a manutenção do bom desempenho das consultas submetidas ao banco de dados. Caso seja constatado um nível de fragmentação entre 5% e 30%, deve-se utilizar a técnica de reorganização. Caso seja um nível maior que 30%, deve-se utilizar a técnica de rebuild. b) A atualização das estatísticas é imprescindível. Mantê-las atualizadas é garantia de bom desempenho da carga de trabalho da instância c) Quando atualizamos as estatísticas de tabelas ou visões indexadas, é preciso ter em mente que a opção FULLSCAN pode ser proibitiva por causa da janela necessária para a execução do comando. Nesses casos, pode-se estabelecer um percentual de sample. d) Índices não utilizados devem ser removidos porque são prejudiciais às cargas de trabalho submetidas aos bancos de dados SQL Server, principalmente se contêm muitas atualizações. e) Analisar as estatísticas de tempos de espera por meio de um job do Agent é fundamental. Se este job indicar que há um volume muito alto de esperas do tipo CXPACKET, é hora de verificar o tráfego nas interfaces de rede conectadas às instâncias, pois esses tipos de espera não são muito comuns. Notas Referências ASSAF, W.; WEST, R.; AELTERMAN, S.; CURNUTT, M. SQL Server 2017 Administration Inside Out. Pearson Education, 2018. BIRD, D. How to setup SQL Server alerts and email operator noti�cations. 2019. Disponível em: https://www.mssqltips.com/sqlservertip/1523/how-to-setup-sql-server-alerts-and-email-operator-noti�cations/. Acesso em: 23 jul. 2020. DELANEY, K.; FREEDMAN, C. Microsoft SQL Server 2012 Internals. Microsoft Press, 2013. KELLEY, K. B. Auditing Failed Logins in SQL Server. 2009. Disponível em: https://www.mssqltips.com/sqlservertip/1735/auditing-failed-logins-in-sql-server/. Acesso em: 23 jul. 2020. MICROSOFT. Resolver a fragmentação do índice reorganizando ou recompilando índices. 2020. Disponível em: https://docs.microsoft.com/pt-br/sql/relational-databases/indexes/reorganize-and-rebuild-indexes?view=sql-server-ver15. Acesso em: 23 jul. 2020. MICROSOFT. DBCC CHECKDB (Transact-SQL). 2017. Disponível em: https://docs.microsoft.com/pt-br/sql/t-sql/database- console-commands/dbcc-checkdb-transact-sql?view=sql-server-ver15. Acesso em: 23 jul. 2020. MICROSOFT. SQL Server Agent. 2017. Disponível em: https://docs.microsoft.com/pt-br/sql/ssms/agent/sql-server-agent? view=sql-server-ver15. Acesso em: 23 jul. 2020. RAIYANI, J. How to identify and resolve SQL Server Index Fragmentation. 2020. Disponível em: https://www.sqlshack.com/how- to-identify-and-resolve-sql-server-index-fragmentation/. Acesso em: 23 jul. 2020. RAMAKRISHNAN, R.; GEHRKE, J. Database management systems. 3. ed. New York: McGraw-Hill, 2002. javascript:void(0); javascript:void(0); javascript:void(0); javascript:void(0); javascript:void(0); javascript:void(0); Próxima aula Explore mais Durante esta última aula da disciplina, nós revisitamos as aulas anteriores e criamos automações para compor nosso arsenal de ferramentas de trabalho. Uma dessas automações respondeu à pergunta: Qual o volume atual dos seus bancos de dados?. Existe outra pergunta, sobre esse mesmo assunto, que certamente também farão a você: Qual será o volume dos seus bancos de dados daqui a 5 anos?. Para responder, você analisará os dados históricos gerados pelo seu job de volumes de bancos de dados. Note que, depois de algum tempo, você terá criado um histórico de crescimento dos seus bancos de dados. Você pode exportá-los para um Excel, por exemplo, e gerar grá�cos de acompanhamento do crescimento dos seus bancos. Mas, como utilizar esses dados históricos para emitir uma estimativa de crescimento dos seus bancos de dados? Pesquise uma solução para esse problema. Implemente a solução. Tenha certeza de que você vai carregar essa ferramenta para onde for. Dicas: Os dados históricos podem ser convertidos em uma série temporal. As linguagens Python e R são ótimas para esse tipo de análise, isto é, gerar forecasts de séries temporais.
Compartilhar