Baixe o app para aproveitar ainda mais
Prévia do material em texto
DESCRIÇÃO As melhores práticas para criação de objetos de banco de dados e para realização de tuning da carga de trabalho submetida ao SQL Server, através de estatísticas e índices. PROPÓSITO Aprender a utilizar os comandos de criação de tabelas, visões, procedimentos armazenados, gatilhos, funções, índices e identificar as funções que cada objeto desempenha no banco de dados. Observar como as consultas e atualizações utilizam os objetos do banco de dados e aprender a utilizar técnicas de tuning para alterar o comportamento da execução dessas operações, com o objetivo de melhorar o desempenho das solicitações emitidas por usuários e aplicações. PREPARAÇÃO Antes de iniciar o conteúdo deste tema, é necessário ter uma instalação de SQL Server 2017 Express Edition ou superior, e a ferramenta de trabalho SQL Server Management Studio, além dos scripts disponíveis para download nos arquivos abaixo, que serão utilizados no decorrer do tema. Criacao_tabelas.sql Criacao_objetos.sql Tuning_estatisticas_indices.sql Caso não seja possível utilizar uma máquina própria para instalar o SQL Server, é possível a utilização de provedores de nuvem, como Azure ou AWS (Amazon Web Services), para implantar uma instância do banco de dados na camada free tier desses provedores, que permitem o uso do produto sem custos por um período predeterminado. OBJETIVOS MÓDULO 1 Reconhecer boas práticas para a criação de tabelas no SQL Server MÓDULO 2 Executar comandos de criação de objetos no SQL Server, como views, stored procedures, triggers, functions e índices MÓDULO 3 Aplicar técnicas de tuning com estatísticas e índices https://stecine.azureedge.net/repositorio/02146/docs/Criacao_tabelas.zip https://stecine.azureedge.net/repositorio/02146/docs/Criacao_objetos.zip https://stecine.azureedge.net/repositorio/02146/docs/Tuning_estatisticas_indices.zip INTRODUÇÃO Uma parte fundamental da utilização do SGBD (Sistema Gerenciador de Banco de Dados) SQL Server para desenvolvimento de aplicações é a criação e manutenção dos objetos que compõem o banco de dados. Nas empresas, é comum encontrar profissionais concentrados em Administração de Dados, responsáveis por criar e manter as estruturas que suportarão o armazenamento e o processamento dos dados. Entre essas estruturas, estão as tabelas, suas propriedades, colunas e restrições. No primeiro módulo deste tema, aprenderemos a criá-las, a especificar suas propriedades e a aplicar as melhores práticas para sua utilização. No segundo módulo, trataremos de outros objetos muito utilizados em bancos de dados SQL Server, como views e stored procedures. Identificaremos as funcionalidades que são implementadas por cada um deles, utilizando exemplos reais de implementação. No terceiro e último módulo, construiremos conhecimento sobre tuning no SQL Server, atividade desempenhada principalmente por administradores de banco de dados (DBA ‒ Database Administrator). O tuning, ou sintonia fina, permite ao DBA alterar como uma consulta é executada pelo otimizador do banco de dados e melhorar o seu desempenho. Para isso, vamos nos apoiar no uso de estatísticas e índices. As capturas de telas que aparecem nas imagens ao longo deste conteúdo são resultantes de comandos elaborados pelo autor no SQL Server Management Studio. MÓDULO 1 Reconhecer boas práticas para a criação de tabelas no SQL Server CRIAÇÃO DE TABELAS Quando uma tabela é criada, alguns metadados devem ser especificados, como o esquema, o nome da tabela, suas colunas e propriedades. Se o esquema não for explicitamente informado, será utilizado o esquema default do usuário que está criando a tabela. Desenvolvedores de sistemas e administradores de dados garantem que esses metadados sejam definidos e validados para que a tabela possa ser criada corretamente. No exemplo a seguir, estamos conectados a uma instância SQL Server 2017 através do SQL Server Management Studio (SSMS). Inicialmente, por meio do comando USE, alteramos o banco de dados corrente. O primeiro comando executado, CREATE SCHEMA, cria o esquema CRM. Vamos utilizar esse esquema para criar todos os objetos, em todos os módulos. No comando CREATE TABLE mostrado a seguir, a tabela Pessoa é criada, no esquema CRM, de acordo com a especificação de suas colunas e propriedades. Criação de tabela CRM Pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Para cada coluna, devemos definir o tipo do dado que será armazenado. 1 No exemplo, id_pessoa tem o tipo int, de forma que essa coluna armazena números inteiros. A coluna tipo_pessoa tem o tipo varchar e quantidade de caracteres 2, de forma que ela armazena até 2 caracteres (no caso, “PF” ou “PJ”). 2 3 Nome_pessoa é do tipo varchar e pode armazenar até 50 caracteres e data_nascimento é do tipo date, que armazena uma data (no formato padrão do banco de dados). As colunas nome_pai e nome_mae são do tipo varchar e armazenam até 50 caracteres, e a coluna renda_mensal é do tipo decimal com até 18 dígitos e precisão de 2 casas decimais. 4 5 Finalmente, a coluna observacao é do tipo varchar e armazena até 300 caracteres. COMENTÁRIO Note que todas as colunas são nomeadas de acordo com o dado que armazenam. Por exemplo, nome_pessoa é naturalmente o nome da pessoa. Já data_nascimento é a data de nascimento da pessoa. É uma boa prática especificar nomes de colunas de forma que os dados ali contidos possam ser identificados rapidamente. Mais na frente, quando você estiver trabalhando com consultas em bancos de dados que possuem, tipicamente, dezenas ou centenas de tabelas, é importante saber quais dados estão sendo solicitados apenas com a leitura de um comando SELECT. No SQL Server, o tamanho máximo de nomes de colunas é 128 caracteres e, portanto, não há necessidade de utilizar abreviações. Além disso, é importante determinar quais são as colunas obrigatórias. Para isso, utiliza-se a cláusula not null. Todas as colunas que possuem essa cláusula devem ser informadas na inserção de uma linha na tabela; caso contrário, um erro será gerado pelo SGBD. Aquelas colunas que possuem a especificação null (ou não possuem tal especificação) são consideradas opcionais. No exemplo, todas as colunas são obrigatórias, exceto nome_pai, nome_mae, renda_mensal e observacao. USO DE RESTRIÇÕES Informação essencial para a criação de uma tabela é a sua chave primária. É essa chave que vai identificar a linha da tabela, assumindo função primordial tanto na implementação do modelo relacional, quanto na implementação das estruturas de dados e seu uso pelo otimizador do SGBD, conforme veremos no módulo de Tuning. Para a tabela CRM.Pessoa, conforme mostrado na imagem anterior, a PRIMARY KEY está definida na coluna id_pessoa e seu valor será incrementado automaticamente a cada inserção. De acordo com a cláusula IDENTITY(1,1), id_pessoa vai começar com o valor 1 e será incrementado de 1 em 1. Assim, toda vez que uma linha for inserida na tabela, o valor de id_pessoa será igual ao último valor inserido na tabela, mais 1. Em seguida, vamos criar uma tabela para armazenar os documentos de uma pessoa. O comando de criação da tabela deve especificar, além das colunas e seus tipos, as chaves da tabela por meio da cláusula CONSTRAINT, que define uma restrição. Além da chave primária, temos uma chave estrangeira que implementa o relacionamento entre o documento e a pessoa. É isso que faz a restrição FOREIGN KEY: implementa chave estrangeira determinando que o valor da coluna id_pessoa da tabela CRM.Pessoa_Documento deve ser um valor existente na coluna id_pessoa da tabela CRM.Pessoa. Na imagem, você pode ver também o uso de ALTER TABLE. É comum que alterações em tabelas existentes sejam necessárias no decorrer da vida útil de um esquema. COMENTÁRIO Novas colunas e novas restrições costumam ser necessárias em manutenções evolutivas. Na construção dada como exemplo, veja como é um ALTER TABLE para adicionar a constraint da chaveestrangeira correspondente à coluna id_pessoa. Criação das restrições da tabela CRM.Pessoa_documento. Captura de tela do software SQL Server Management Studio (SSMS). Veja nos endereços a seguir: Uma referência completa sobre o comando CREATE TABLE. https://docs.microsoft.com/pt-br/sql/t-sql/statements/create-table-transact-sql?view=sql-server- ver15, Uma referência completa sobre o comando ALTER TABLE. javascript:void(0); https://docs.microsoft.com/pt-br/sql/t-sql/statements/alter-table-transact-sql?view=sql-server- ver15 ATIVIDADE PRÁTICA Considerando que as tabelas mostradas anteriormente estão criadas no seu banco de dados, crie a tabela CRM.Pessoa_Endereco, com as seguintes características: A chave primária da tabela deve ser gerada automaticamente por meio de incremento de 1 sobre o último valor inserido na tabela; Deve existir uma chave estrangeira que estabeleça o relacionamento com a tabela CRM.Pessoa; As colunas das tabelas devem ser tipo_endereco (somente os valores Residencial, Comercial ou Outro), tipo_logradouro, logradouro, número, complemento, bairro, cidade, estado e CEP. O valor da coluna [complemento] deve ser opcional. Todos os outros devem ser obrigatórios. SOLUÇÃO Solução da Atividade Prática, elaborada por Antony Seabra de Medeiros. Captura de tela do software SQL Server Management Studio (SSMS). javascript:void(0); INSERÇÃO E RECUPERAÇÃO DE INFORMAÇÕES Com as tabelas já criadas no banco de dados, é possível inserir dados por meio do comando INSERT e recuperá-los através do comando SELECT. Com respeito aos tipos de dados e às restrições impostas para cada coluna da tabela, o comando INSERT informa os dados da linha a ser inserida. Inserção de dados nas tabelas CRM.Pessoa e CRM.Pessoa_documento. Captura de tela do software SQL Server Management Studio (SSMS). ATENÇÃO Observe que, na inserção da linha na tabela Pessoa, os valores para as colunas nome_pai, nome_mae e observacao não foram informados. O INSERT é executado com sucesso porque essas não são colunas obrigatórias. Ainda, na inserção da linha na tabela CRM.Pessoa_Documento, a data é informada de acordo com o formato padrão do banco de dados. No exemplo, está sendo utilizado o formato norte- americano [YYYY-MM-DD], mas você pode utilizar o formato mais adequado para sua aplicação por meio da função CONVERT. Veja no endereço a seguir todos os estilos de data possíveis e como utilizar a função CONVERT: https://docs.microsoft.com/pt-br/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql- server-ver15 A recuperação dos dados é realizada por meio do comando SELECT. Na imagem anterior, estão recuperadas todas as colunas [*] da tabela CRM.Pessoa e da tabela CRM.Pessoa_Documento. DICA Quando for necessário recuperar dados de duas ou mais tabelas, utilizamos o operador JOIN informando como as tabelas se relacionam. No exemplo mostrado na próxima imagem, para recuperar o nome da pessoa, sua data de nascimento e os documentos da pessoa, com o tipo e data de expedição, utilizamos o operador JOIN entre as tabelas CRM.Pessoa e CRM.Pessoa_Documento, especificando como elas se relacionam. Seleção de dados nas tabelas CRM.Pessoa e CRM.Pessoa_documento. Captura de tela do software SQL Server Management Studio (SSMS). A cláusula ON informa que o relacionamento entre as duas tabelas ocorre quando o valor de id_pessoa em CRM.Pessoa é igual ao valor de id_pessoa em CRM.Pessoa_Documento. Muito embora tenhamos definido uma restrição do tipo chave estrangeira na definição da tabela CRM.Pessoa_Documento, não é essa restrição que torna o relacionamento possível. Ele javascript:void(0); poderia ser feito dessa mesma forma, mesmo que não tivéssemos definido a chave estrangeira. Entretanto, é uma boa prática que todos os relacionamentos entre as tabelas sejam definidos por meio de chaves estrangeiras. Essa boa prática garante que os valores da coluna id_pessoa em CRM.Pessoa_Documento existam, de fato, na tabela CRM.Pessoa. USO DE IMAGENS EM TABELAS Uma necessidade bastante comum é o armazenamento de imagens em bancos de dados. No SQL Server, podemos lançar mão de colunas VARBINARY(MAX) e, opcionalmente, a especificação FILESTREAM. A diferença básica entre elas é que: A imagem é armazenada como um BLOB (Binary Large Object) dentro do banco de dados quando usamos somente VARBINARY(MAX) E a imagem é armazenada fora do banco de dados quando usamos FILESTREAM, como um arquivo do sistema operacional. Para exemplificar o uso de VARBINARY(MAX), vamos criar uma tabela para armazenar as imagens associadas aos documentos das pessoas. A tabela vai se chamar CRM.Pessoa_Imagem e vai conter uma coluna que aponta para CRM.Pessoa_Documento, e outra coluna para armazenar a imagem propriamente dita. Veja como fica o comando para criação da tabela na imagem a seguir: Criação da tabela CRM.Pessoa_Imagem. Captura de tela do software SQL Server Management Studio (SSMS). Para inserir uma linha nessa tabela, vamos utilizar a função OPENROWSET passando o caminho da imagem que queremos inserir na coluna, além do índice do documento. COMENTÁRIO Observe que cuidamos para que a coluna fosse não obrigatória, para o caso de imagens que não estão associadas a documentos. Veja a seguir como fica a inserção da linha e, logo após, um SELECT com JOIN nas tabelas CRM.Pessoa, CRM.Pessoa_Documento e CRM.Pessoa_Imagem, para recuperar as imagens associadas a documentos. SELECT recuperando a coluna imagem. Captura de tela do software SQL Server Management Studio (SSMS). O retorno mostra o valor hexadecimal correspondente ao tipo BLOB armazenado na coluna. Esse valor é uma representação da imagem que, se convertido apropriadamente, gera a imagem original. Veja mais detalhes sobre VARBINARY(MAX) e outros tipos de dados avançados no endereço a seguir: https://docs.microsoft. com/pt-br/sql/connect/jdbc/using -advanced-data-types ?view=sql-server- ver15 Da mesma forma que importamos um arquivo de imagem para dentro do banco de dados, podemos exportá-lo de volta para um arquivo imagem, permitindo que uma aplicação possa exibi-la. Essa exportação da imagem para o arquivo pode ser feita pelo utilitário BCP do SQL Server. Na construção a seguir, a string @sql é criada com o comando BCP, recebendo o valor hexadecimal que retorna da coluna imagem e escrevendo no arquivo especificado em QUERYOUT. javascript:void(0); O arquivo .fmt é o arquivo auxiliar de formato gerado automaticamente em uma exportação do BCP e o parâmetro –S especifica o servidor onde ele será executado; no exemplo, @@SERVERNAME especifica o próprio servidor onde estamos conectados com o SSMS. O último passo é executar o conteúdo de @sql através da procedure do SQL Server, xp_cmdshell. Após essa execução, a imagem está pronta no caminho especificado. Exportação da imagem com BCP. Captura de tela do software SQL Server Management Studio (SSMS). As imagens em uma coluna do tipo VARBINARY(MAX) podem ser armazenadas fora do banco de dados, por meio da especificação FILESTREAM. Você pode realizar as mesmas operações que fizemos até aqui; a diferença está na criação da tabela. Veja a seguir: Criação da tabela utilizando FILESTREAM. Captura de tela do software SQL Server Management Studio (SSMS). Observe a especificação FILESTREAM logo após o tipo da coluna VARBINARY(MAX). Quando a tabela é criada com esse comando, o SQL Server verifica se existe um FILEGROUP no banco de dados criado especialmente para o armazenamento de filestreams. Caso exista, todas as imagens são armazenadas no caminho correspondente ao FILEGROUP. Você pode ver no script do módulo uma construção preparada para criar um banco de dados habilitado para FILESTREAM e mais detalhes sobre o uso de filestreams no SQL Server no endereço: https://docs.microsoft. com/pt-br/sql/relational-databases /blob/filestream-sql -server?view=sql- server-ver15 CRIAÇÃO DE TABELAS NO SQL SERVERNo vídeo a seguir, demonstramos a criação de tabelas no SQL Server utilizando um ambiente real e captura dos procedimentos. VERIFICANDO O APRENDIZADO javascript:void(0); 1. A RESPEITO DOS CONCEITOS E MELHORES PRÁTICAS PARA CRIAÇÃO DE TABELAS NO SQL SERVER, ASSINALE A AFIRMATIVA FALSA. A) É uma boa prática nomear as colunas de uma tabela de acordo com o dado que ali será armazenado. Isso vai permitir identificar rapidamente qual informação está sendo solicitada em uma consulta, por exemplo. B) A criação de tabelas no SQL Server tem papel fundamental tanto na implantação de um modelo relacional quanto na execução das solicitações submetidas pelos usuários ao banco de dados. C) O uso de restrições na construção de tabelas é uma boa prática na criação e manutenção das tabelas do banco de dados. Chaves primárias e chaves estrangeiras são duas das principais restrições utilizadas. D) Uma constraint do tipo CHECK permite enumerar os valores que uma dada coluna pode conter. E) Entre os metadados que devem ser informados na criação de uma tabela, estão o esquema e o nome da tabela. Caso um deles não seja informado, será gerado um erro pelo SGBD. 2. CONSIDERE QUE AS SEGUINTES ALTERAÇÕES FORAM REALIZADAS NAS ESTRUTURAS DAS TABELAS CRM.PESSOA E CRM.PESSOA_DOCUMENTO: • COLUNA [ESTADO CIVIL] ADICIONADA À TABELA CRM.PESSOA, COM OS VALORES POSSÍVEIS RESTRITOS AOS ESTADOS [SOLTEIRO, CASADO, SEPARADO, DIVORCIADO, VIÚVO]. • TABELA DE CRM.ORGAOS CRIADA NO BANCO DE DADOS. • COLUNA [ORGAO_EXPEDIDOR] ADICIONADA À TABELA CRM.PESSOA_DOCUMENTO. SEUS VALORES POSSÍVEIS SÃO SOMENTE AQUELES EXISTENTES NA TABELA CRM.ORGAOS. ASSINALE A AFIRMATIVA INCORRETA EM RELAÇÃO ÀS ALTERAÇÕES NO BANCO DE DADOS. A) Foi criada uma chave estrangeira na coluna [Orgao_Expedidor] da tabela CRM.Pessoa_Documento, apontando para a tabela CRM.Orgaos. B) A tabela CRM.Orgaos foi criada no banco de dados, contendo uma coluna para armazenar o órgão expedidor. C) Foi utilizada uma restrição do tipo CHECK para assegurar que somente os estados civis enumerados possam ser utilizados. D) A chave primária da tabela CRM.Orgaos deve ser um código numérico que identifique unicamente o órgão expedidor, podendo ser gerado automaticamente pela função IDENTITY. E) A lista de estados civis poderia ser inserida em uma tabela CRM.Estado_Civil e a coluna [Estado_Civil] poderia ter uma chave estrangeira apontando para esta tabela. GABARITO 1. A respeito dos conceitos e melhores práticas para criação de tabelas no SQL Server, assinale a afirmativa falsa. A alternativa "E " está correta. O esquema default, do usuário que está criando a tabela, será utilizado se o esquema não tiver sido explicitamente informado. Para que a tabela seja criada de forma correta, os desenvolvedores de sistemas e administradores de dados procuram garantir que esses metadados sejam definidos e validados. 2. Considere que as seguintes alterações foram realizadas nas estruturas das tabelas CRM.Pessoa e CRM.Pessoa_Documento: • Coluna [Estado Civil] adicionada à tabela CRM.Pessoa, com os valores possíveis restritos aos estados [Solteiro, Casado, Separado, Divorciado, Viúvo]. • Tabela de CRM.Orgaos criada no banco de dados. • Coluna [Orgao_Expedidor] adicionada à tabela CRM.Pessoa_Documento. Seus valores possíveis são somente aqueles existentes na tabela CRM.Orgaos. Assinale a afirmativa INCORRETA em relação às alterações no banco de dados. A alternativa "D " está correta. A chave primária da tabela CRM.Orgaos pode ser o próprio [Orgao_Expedidor]. Não é necessário que a chave primária seja um código numérico. MÓDULO 2 Executar comandos de criação de objetos no SQL Server, como views, stored procedures, triggers, functions e índices CRIAÇÃO DE VIEWS As views, ou visões, permitem que uma consulta SQL seja apresentada como uma tabela do banco de dados, de modo que desenvolvedores e usuários possam utilizá-las sem conhecer os detalhes que tornam a consulta possível. No módulo anterior, criamos uma consulta que faz um JOIN entre as tabelas CRM.Pessoa e CRM.Pessoa_Documento para recuperar os documentos de uma pessoa. Será que toda vez que uma consulta desse tipo for necessária, será preciso escrevê-la novamente, conhecendo as tabelas, suas colunas e as colunas de correlação entre as tabelas? Veja o exemplo a seguir: Criação da view CRM.vw_pessoa_documento. Captura de tela do software SQL Server Management Studio (SSMS). Observe que podemos usar a visão CRM.Pessoa_documento sem conhecer os detalhes da sua implementação; apenas utilizamos suas colunas para, adicionalmente, filtrar os resultados e/ou ordená-los. Outra consequência relevante para a administração do banco de dados é que o acesso de leitura para um usuário pode ser concedido na view, sem necessariamente conceder o acesso às tabelas. Isso faz com que o usuário possa executar o SELECT na view, mas não possa executar o SELECT nas tabelas que a view utiliza. Em bancos de dados que possuem dezenas ou centenas de tabelas, as visões desempenham papel fundamental para desenvolvedores e usuários. Tornam as solicitações mais simples, enquanto promovem boas práticas de administração e segurança. Para ver mais detalhes sobre a criação de visões no SQL Server, acesse o endereço: https://docs.microsoft.com/ pt-br/sql/t-sql/statements/ create-view-transact-sql? view=sql-server- ver15 ATIVIDADE PRÁTICA Considerando que as tabelas Pessoa, Pessoa_Documento e Pessoa_Endereco estão criadas em seu banco de dados, crie uma visão com as seguintes características: javascript:void(0); Retorna todos os dados de Pessoa; Permite filtrar pelo tipo do documento; Retorna somente o endereço residencial da pessoa. SOLUÇÃO Solução da Atividade Prática, elaborada por Antony Seabra de Medeiros. Captura de tela do software SQL Server Management Studio (SSMS). CRIAÇÃO DE STORED PROCEDURES As stored procedures, ou procedimentos armazenados, permitem que um conjunto de tarefas seja implementado (em linguagem SQL) e armazenado no banco de dados, criando um procedimento que pode ser executado por meio de uma única chamada. EXEMPLO Exemplos clássicos são os procedimentos de inserção, atualização e deleção de linhas de uma tabela. Esses procedimentos, tipicamente, fazem críticas dos dados a serem inseridos ou atualizados, podendo ainda fazer transformações ou cálculos para gerar novos dados. Veja a seguir uma possível implementação do procedimento de inserção na tabela CRM.Pessoa. Criação da stored procedure CRM.proc_insere_pessoa. Captura de tela do software SQL Server Management Studio (SSMS). O procedimento determina quais parâmetros de entrada são esperados, precedidos do caractere @, e também o tipo de dado esperado para cada um deles. Caso o procedimento seja chamado com um tipo não correspondente, o próprio SGBD gera um erro. Caso todos os parâmetros atendam aos requisitos especificados, o procedimento pode ser executado. Seu corpo, codificado entre o BEGIN e o END, faz, inicialmente, uma crítica em relação aos parâmetros @tipo_pessoa, @nome_pessoa e @data_nascimento, verificando se algum deles contém o valor nulo e, em caso positivo, emite uma mensagem de erro (comando RAISERROR). Na sequência, verifica se existe na tabela CRM.Pessoa uma linha que contenha os valores de @nome_pessoa e @data_nascimento. Em caso negativo, insere a linha na tabela; em caso positivo, retorna uma mensagem informando “Pessoa já cadastrada. ”. Execução da stored procedure CRM.proc_insere_pessoa. Captura de tela do software SQL Server Management Studio (SSMS). A chamada ao procedimento armazenado é realizada com o comando EXECUTE (ou EXEC), informando o nome do procedimento e os parâmetros correspondentes. Conforme pode ser constatado na imagem anterior, após a execução do procedimento, a linha correspondente ao id_pessoa = 2 é inserido na tabela CRM.Pessoa. Uma stored procedure responsável pela deleção de uma linha deve verificar,por exemplo, se realmente existe uma linha na tabela com os valores passados como parâmetros. Caso exista, prossegue com o DELETE na tabela. Veja um exemplo a seguir, considerando que somente a chave primária id_pessoa será utilizada como parâmetro. Criação e execução da stored procedure CRM.proc_deleta_pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Uma execução do procedimento armazenado, passando como parâmetro o valor 2, faz com que seja verificada a existência da linha correspondente a id_pessoa = 2. Como a linha, de fato, existe, será executado o comando DELETE na tabela CRM.Pessoa, com a cláusula WHERE definindo o valor da chave primária. O procedimento para atualização de linhas da tabela, por sua vez, precisa checar, além dos parâmetros obrigatórios, a existência da linha correspondente a id_pessoa. Caso exista, será executado o comando UPDATE na tabela CRM.Pessoa, com a cláusula WHERE definindo o valor da chave primária. Veja na imagem a seguir: Criação da stored procedure CRM.proc_atualiza_pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Caso o SELECT 1 não retorne nenhuma linha, então o UPDATE não é realizado e a mensagem 'Pessoa não cadastrada.' é retornada. COMENTÁRIO Você deve ter observado, em todas as procedures que criamos até aqui, o uso desse SELECT 1 para verificar a existência de uma determinada linha. Essa é uma boa prática quando queremos apenas verificar se uma ou mais linhas existem, sob determinadas condições. Nesses casos, não queremos recuperar qualquer informação, apenas verificar que a linha existe. Assim, não faz sentido enumerar colunas a serem recuperadas. Caso a linha exista, o valor 1 será retornado e o EXISTS será avaliado como true. Caso contrário, nada será retornado e o EXISTS será avaliado como false. Veja mais detalhes sobre stored procedures e seus usos no endereço: https://docs.microsoft.com/pt-br/sql/t-sql/statements/create-procedure-transact-sql?view=sql- server-ver15 CRIAÇÃO DE TRIGGERS Os triggers, ou gatilhos, permitem que uma tarefa seja disparada na ocorrência de um evento, como uma inserção, deleção ou atualização. Essa tarefa pode ser desde um pequeno código SQL informado na própria definição do trigger até a execução de uma stored procedure que codifica diversas tarefas adicionais. De fato, é bastante comum o uso de gatilhos para automatizar tarefas que devem ser executadas antes ou depois dos principais eventos de manipulação de dados em tabelas, sendo que no SQL Server só é possível criar gatilhos AFTER (ou FOR) e INSTEAD OF; não é possível criar um gatilho do tipo BEFORE, muito embora seja possível simular a sua execução. COMENTÁRIO Entre as tarefas que podem ser implementadas por meio de gatilhos, podemos encontrar auditoria de dados, integração entre sistemas e monitoração da atualização de dados. Em relação à auditoria de dados, alguns sistemas precisam saber sobre as datas em que as linhas são criadas e/ou atualizadas nas tabelas. Para implementar uma funcionalidade desse tipo, pode-se utilizar triggers. Logo após a inserção ou atualização de um registro, um código SQL é executado para gravar a data e hora do sistema na coluna data_ultima_atualizacao da tabela correspondente. Dessa forma, toda vez que um INSERT ou UPDATE na tabela forem executados, o SGBD atualiza essa coluna com a data e hora atuais. Para implementar o gatilho em nossa tabela CRM.Pessoa, vamos criar primeiro a coluna data_ultima_atualizacao com o tipo datetime. Em seguida, vamos criar o trigger na tabela, conforme a imagem a seguir: javascript:void(0); Criação do trigger CRM.trg_Pessoa_data_atualizacao. Captura de tela do software SQL Server Management Studio (SSMS). A implementação do trigger conta com uma tabela especial, mantida pelo próprio SGBD, chamada Inserted. Inserted é uma tabela virtual e contém a imagem da linha inserida ou atualizada, com as mesmas colunas da tabela original. É por meio dela que recuperamos o valor de id_pessoa, para que o UPDATE da coluna data_ultima_atualizacao possa ser executado na linha correta, ou seja, na linha que acabou de ser atualizada. Executando-se a stored procedure para atualizar uma linha da tabela, o gatilho é disparado e o código correspondente, executado. Veja, a seguir, a imagem final da linha na tabela CRM.Pessoa. Teste de execução do trigger CRM.trg_Pessoa_data_atualizacao. Captura de tela do software SQL Server Management Studio (SSMS). Existe também a tabela virtual Deleted, que contém a imagem da linha antes de ser excluída por um comando DELETE. EXEMPLO Você pode utilizar a tabela Deleted em um trigger para criar uma rotina de archive dos seus registros. Muitos sistemas implementam uma funcionalidade desse tipo, pois devem armazenar os registros apagados por um determinado período para fins de auditoria. O primeiro passo é criar uma tabela idêntica à original. Na imagem a seguir, você pode ver o CREATE TABLE da tabela CRM.Pessoa_archive. É nela que serão gravadas as linhas removidas da tabela CRM.Pessoa. Criação da tabela CRM.Pessoa_archive. Captura de tela do software SQL Server Management Studio (SSMS). O segundo passo é criar o trigger de delete na tabela CRM.Pessoa, pois queremos criar um registro na tabela CRM.Pessoa_archive quando houver uma deleção na tabela CRM.Pessoa. Em outras palavras, queremos copiar o registro da CRM.Pessoa para a tabela CRM.Pessoa_archive quando esse registro for excluído. Sua implementação utiliza uma construção INSERT SELECT. Com ela, você pode inserir uma linha em tabela utilizando linhas de outra. É exatamente o que queremos: inserir uma linha na tabela CRM.Pessoa_archive, utilizando os dados da linha que foi removida da tabela CRM.Pessoa. Esses dados estão na tabela Deleted. Veja a seguir o código. Criação do trigger CRM.trg_Pessoa_deleta. Captura de tela do software SQL Server Management Studio (SSMS). O gatilho trg_Pessoa_deleta é disparado após o delete na tabela CRM.Pessoa e executa um INSERT na tabela de archive utilizando todas as colunas da tabela Deleted. Para testá-lo, executamos a stored procedure CRM.proc_deleta_pessoa, passando como parâmetro o valor 2. Isso faz com que a linha com id_pessoa=2 seja deletada da tabela CRM.Pessoa e, logo após, inserida na tabela CRM.Pessoa_archive. Veja o SELECT nas duas tabelas logo após a execução do delete: Teste de execução do trigger CRM.trg_Pessoa_deleta. Captura de tela do software SQL Server Management Studio (SSMS). Como esperávamos, a linha removida da tabela original foi inserida na tabela de archive, preservando os dados para consultas sob demanda. Muitos sistemas utilizam essa mesma abordagem de archive para remover da tabela principal dados muito antigos, salvando-os em uma outra tabela, de onde possam ser consultados caso haja necessidade. Veja mais detalhes sobre triggers e seus usos no endereço: https://docs.microsoft.com/pt-br/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server- ver15 javascript:void(0); CRIAÇÃO DE FUNCTIONS As functions, ou funções, assim como as stored procedures, permitem que um conjunto de tarefas seja implementado (em linguagem SQL) e armazenado no banco de dados. A principal diferença entre as functions e as stored procedures é que a função deve, necessariamente, retornar um valor. Outra característica importante das funções no SQL Server é que elas não podem alterar dados em tabelas, ou seja, não são permitidos INSERTs, UPDATEs ou DELETEs. Vamos ver o exemplo de uma função que, dada uma data de nascimento, retorna o valor da idade correspondente. Criação da função CRM.fn_idade. Captura de tela do software SQL Server Management Studio (SSMS). A função recebe uma data como parâmetro e retorna um valor inteiro. Essas são as duas primeiras informações que podemos extrair ao ler o cabeçalho de definição da função. A cláusula RETURNS especifica que tipo de dadoa função retorna. No SQL Server, o retorno de uma função pode ser um valor escalar ou uma tabela. A função com valor escalar retorna um único valor e a função com valor de tabela retorna um conjunto de linhas. No exemplo anterior, vamos retornar um único valor inteiro, que é a idade correspondente à data de nascimento passada como parâmetro. Para realizar o cálculo, o código utiliza a função DATEDIFF para calcular a diferença entre a data de nascimento e a data atual do sistema, em anos. É exatamente esse o valor atribuído à variável @idade, que é o valor de retorno da função. Veja o seu uso na imagem a seguir: Utilização da função CRM.fn_idade. Captura de tela do software SQL Server Management Studio (SSMS). A função pode ser utilizada diretamente no SELECT. Na imagem anterior, você pode ver que recuperamos nome_pessoa e data_nascimento de CRM.Pessoa. Passando o valor de data_nascimento para a função CRM.fn_idade no SELECT, podemos recuperar a idade correspondente de cada pessoa selecionada. Veja a referência de CREATE FUNCTION no endereço: https://docs.microsoft.com/pt-br/sql/t-sql/statements/create-function-transact-sql?view=sql- server-ver15 CRIAÇÃO DE ÍNDICES Quando uma consulta SQL é executada no banco de dados, o SGBD pode percorrer a tabela inteira para recuperar os dados solicitados. Vamos rever o último SELECT executado no tópico anterior: SELECT nome_pessoa, data_nascimento, CRM.fn_idade(data_nascimento) FROM CRM.Pessoa Para executar essa consulta, o SGBD percorre todas as linhas da tabela CRM.Pessoa, uma a uma. Para cada uma delas, recupera as colunas solicitadas e invoca a função CRM.fn_idade para calcular a idade da pessoa. No final, mostra todas as linhas da tabela e as colunas solicitadas. Agora, veja este outro exemplo a seguir: SELECT nome_pessoa, data_nascimento, CRM.fn_idade(data_nascimento) FROM CRM.Pessoa WHERE data_nascimento >= '2020/01/01' javascript:void(0); Para executar essa consulta, o SGBD percorre todas as linhas da tabela CRM.Pessoa, uma a uma. Para cada uma delas, verifica se o valor de data_nascimento é maior ou igual a '2020/01/01'. Em caso positivo, recupera as colunas solicitadas e invoca a função CRM.fn_idade para calcular a idade da pessoa. No final, mostra todas as linhas da tabela e as colunas solicitadas, somente para as linhas que satisfizeram a condição da cláusula WHERE. Observe que, em ambas as consultas, o SGBD percorre a tabela inteira para recuperar os resultados. Na primeira consulta, o solicitante, de fato, deseja recuperar todas as linhas, pois não há qualquer condição definida. Entretanto, na segunda, existe uma condição definida por data_nascimento >= '2020/01/01'. O solicitante deseja recuperar apenas as linhas que satisfazem essa condição. Para isso, o SGBD precisa realmente percorrer todas as linhas da tabela para verificar aquelas que satisfazem a condição? Índices são estruturas de acesso especiais, que permitem ao SGBD localizar as linhas de uma tabela baseado em uma ou mais colunas. Podemos criar um índice na coluna data_nascimento, de forma que o SELECT não tenha que percorrer toda a tabela para encontrar linhas que satisfaçam a uma condição dada, baseada nessa coluna. EXEMPLO O SGBD pode utilizar esse índice para localizar mais rapidamente apenas as linhas com data_nascimento >= '2020/01/01. Para trabalhar adequadamente com índices e mostrar o real impacto que ele pode trazer para as consultas submetidas a um banco de dados, vamos executar uma carga de dados na tabela CRM.Pessoa. Observe o código SQL a seguir: Carga na tabela CRM.Pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Queremos que a tabela tenha um total de 100.000 linhas. Como ela já tem 2 (recriamos a linha de Ada Lovelace deletada anteriormente), o loop WHILE começa em 2 e vai até 100000. Em cada iteração, a variável é incrementada e a função NEWID() é utilizada para gerar um valor aleatório do tipo uniqueidentifier. Você pode testar seu uso em conjunto com a função CHECKSUM e ABS, conforme mostrado a seguir: SELECT ABS(CHECKSUM(NEWID()) A função NEWID() gera um uniqueidentifier de 16 bytes. A função CHECKSUM converte esse valor em um número com 9 ou 10 dígitos. A função ABS retorna seu valor absoluto. Com esse valor, podemos gerar outros valores, de acordo com o tipo de dado. Para @nome_pessoa, usamos a função CONVERT para converter esse valor em uma string de até 50 caracteres. Para @data_nascimento, dividimos o valor gerado por 100.000 e multiplicamos por -1, para que seja diminuído da data atual, recuperada por meio da função GETDATE(), convertida para um tipo date. Para @renda_mensal, o valor aleatório é simplesmente dividido por 100.000. Após a execução do código, podemos ver o resultado. Validação da carga da tabela CRM.Pessoa. Captura de tela do software SQL Server Management Studio (SSMS). COUNT(*) confirma que temos 100.000 linhas na tabela. Executando um SELECT TOP(10), temos os valores gerados para as colunas nome_pessoa, data_nascimento e renda_mensal das 10 primeiras linhas, confirmando também os valores aleatórios gerados. Em seguida, vamos observar o comportamento da consulta dada como exemplo anteriormente. Seleção de dados da tabela CRM.Pessoa após a carga. Captura de tela do software SQL Server Management Studio (SSMS). Observe, no canto inferior direito, o total de 2.294 linhas que satisfazem a condição especificada para a coluna data_nascimento. Isso nos diz que, das 100.000 linhas da tabela, 2.294 possuem data_nascimento >= '2020/01/01'. Para ver como o SGBD resolve a consulta, você pode usar as teclas CTRL-L, com a query selecionada, para ver o seu Plano de Execução. Plano de execução utilizando Scan. Captura de tela do software SQL Server Management Studio (SSMS). Observe o operador Clustered Index Scan, que indica uma varredura completa (Scan) na tabela (índice clusterizado). Toda tabela que contém uma chave primária é criada como um índice clusterizado. Sua ordenação física nos blocos de disco segue a ordenação da chave primária. COMENTÁRIO Quando não há uma chave primária, a tabela é criada como uma heap. Como não existe um índice pela coluna data_nascimento, essa é a única opção que o SGBD tem para recuperar os dados da consulta. Para criar um índice nessa coluna, vamos usar o comando CREATE INDEX, conforme a imagem a seguir: Criação do índice não clusterizado. Captura de tela do software SQL Server Management Studio (SSMS). Com essa instrução, estamos criando o índice ind_Pessoa_data_nascimento (não clusterizado) para a tabela CRM.Pessoa, na coluna data_nascimento. Após a criação, o SGBD pode usar o índice para resolver a consulta SQL. Fazendo essa mesma consulta com diferentes valores de data, podemos ver quando o SGBD utiliza uma varredura completa na tabela (Scan) ou uma busca pelo índice (Seek). Veja, a seguir, um exemplo de uso do índice que acabamos de criar. Plano de execução utilizando Seek. Captura de tela do software SQL Server Management Studio (SSMS). O que o plano de execução nos mostra é o uso do índice não clusterizado ind_Pessoa_data_nascimento. Para cada chave encontrada nesse índice que satisfaz a condição especificada no WHERE, é realizada a pesquisa da chave primária na tabela CRM.Pessoa, e a recuperação dos dados solicitados. ATENÇÃO Note que essa estratégia é bem diferente da varredura completa da tabela. Por meio do índice, o SGBD foi capaz de localizar diretamente as chaves que satisfizeram a condição data_nascimento>= '2021/05/01'. Para mais detalhes sobre a criação de índices, consulte o endereço a seguir: https://docs.microsoft.com/pt-br/sql/t-sql/statements/create-index-transact-sql?view=sql-server- ver15 javascript:void(0); OS PARADIGMAS DE COMUNICAÇÃO EM COMPUTAÇÃO DISTRIBUÍDA A criação de objetos no SQL Server, utilizando um ambiente real, e a captura dos procedimentos são apresentadasno vídeo a seguir. VERIFICANDO O APRENDIZADO 1. A RESPEITO DO USO DE VIEWS, STORED PROCEDURES, TRIGGERS E FUNCTIONS NO SQL SERVER, ASSINALE A ALTERNATIVA INCORRETA. A) As visões são uma boa prática de programação em bancos de dados SQL Server, especialmente quando há muitas tabelas envolvidas em consultas frequentes. Nesses casos, cria-se uma visão genérica que implementa os joins das tabelas, permitindo ao desenvolvedor utilizar a visão e especificar seus critérios na cláusula WHERE. B) Trigger é um recurso muito utilizado na implementação de bancos de dados SQL Server. Pode-se, por exemplo, criar um gatilho para executar um código SQL antes ou após a execução de um comando INSERT, UPDATE ou DELETE. C) No SQL Server, as stored procedures são muito utilizadas para implementar tarefas que, frequentemente, contém diversas atualizações de tabelas do banco de dados. Elas podem receber parâmetros e retornar resultados. D) A diferença entre uma stored procedure e uma função é que a última deve necessariamente retornar um resultado. E) No SQL Server, as funções podem retornar um valor escalar ou um resultset, que corresponde a um valor de tabela. 2. UMA TABELA FOI CRIADA NO SQL SERVER, CONTENDO UMA CHAVE PRIMÁRIA INTEIRA. QUE TIPO DE ESTRUTURA DE DADOS IMPLEMENTA A TABELA? A) Índice clusterizado B) Índice não clusterizado C) Heap D) Tabela Hash E) Índice binário GABARITO 1. A respeito do uso de views, stored procedures, triggers e functions no SQL Server, assinale a alternativa INCORRETA. A alternativa "B " está correta. No SQL Server, não há triggers BEFORE; existem somente os tipos AFTER (ou FOR) e INSTEAD OF. 2. Uma tabela foi criada no SQL Server, contendo uma chave primária inteira. Que tipo de estrutura de dados implementa a tabela? A alternativa "A " está correta. O índice clusterizado é a estrutura de dados padrão para uma tabela que possui chave primária definida. MÓDULO 3 Aplicar técnicas de tuning com estatísticas e índices SELETIVIDADE O componente do SGBD responsável por gerar o plano de execução de uma consulta é o otimizador de consultas. A atividade de tuning, também chamada de sintonia fina, consiste, essencialmente, em alterar o comportamento do otimizador do SGBD, visando melhorar o desempenho das consultas submetidas ao banco de dados. Entretanto, como o otimizador decide qual plano de execução usar? Como ele decide se vai varrer uma tabela inteira ou usar um índice? Voltando ao exemplo dado no módulo anterior, por que o otimizador decidiu usar o índice, em vez de varrer a tabela inteira, quando o predicado data_nascimento >= '2020/01/01' foi substituído por data_nascimento >= '2021/05/01'? O conceito de seletividade é fundamental para responder a essa pergunta. Dizemos que um predicado tem seletividade alta quando faz a consulta retornar um percentual pequeno de linhas da tabela. Por outro lado, dizemos que um predicado tem seletividade baixa quando faz a consulta retornar um percentual grande de linhas da tabela. Quanto maior a seletividade, maior a probabilidade do otimizador escolher usar o índice correspondente. Por que o índice foi utilizado com o predicado data_nascimento >= '2021/05/01'? Porque a seletividade foi alta o suficiente para fazer com que o otimizador escolhesse esse plano de execução, que utiliza o índice não clusterizado. Na verdade, o que realmente importa para otimizador é que essa seletividade faz com que o custo do plano de execução, que utiliza o índice não clusterizado, seja menor que o custo do plano de execução que utiliza o índice clusterizado. Vamos, então, visualizar os custos que o próprio SQL Server nos mostra. Posicionando o cursor sobre o operador Scan do plano de execução da consulta correspondente ao predicado data_nascimento >= '2020/01/01', temos a janela mostrada a seguir: Imagem: Antony Seabra de Medeiros. Custos e estimativas do operador Scan. Observe os custos e as estimativas. Há um custo associado ao processamento (CPU) e outro associado à leitura de dados (E/S). Note que o maior custo está, de fato, na leitura dos dados, que representa aproximadamente 87% do custo total. Em relação às estimativas, a informação fornecida ao otimizador é que ele vai percorrer 2.282 linhas, de um total de 100.000, cada uma com tamanho médio de 39 bytes. Com base nesses custos e estimativas, o otimizador decide varrer a tabela inteira por meio de um clustered index scan. Em seguida, vamos verificar o plano de execução da consulta correspondente ao predicado data_nascimento >= '2021/05/01'. Posicionando o cursor sobre os dois operadores do plano, temos as janelas mostradas a seguir: Imagem: Antony Seabra de Medeiros. Custos e estimativas do operador Seek. Vamos começar pelo operador Index Seek. De fato, é por ele que a busca será iniciada. Observe os custos e as estimativas. Há um custo associado ao processamento (CPU) e outro associado à leitura de dados (E/S). Novamente, o maior custo está associado à leitura dos dados, que representa aproximadamente 93% do custo total. Em relação às estimativas, a informação que o otimizador tem é que vai percorrer 42 linhas, cada uma com tamanho médio de 14 bytes. Nessa estratégia do otimizador, para cada chave recuperada do índice, será realizada uma pesquisa na tabela principal (lookup), para recuperar a linha correspondente. Para esse operador, que representa 97% do custo total do plano, temos a estimativa de leitura de 1 linha para cada uma das 42 execuções. ATENÇÃO Com base nesses custos e estimativas, o otimizador decide percorrer o índice por meio de um non-clustered index seek e, para cada linha encontrada que satisfaça à condição estabelecida, fazer o lookup na tabela principal. O que chama nossa atenção nesse plano é seu custo total, quando comparado ao do plano anterior que utilizou o Scan. Muito embora estejamos comparando consultas diferentes, é possível ter uma ideia da diferença associada ao uso do índice não clusterizado. Note que o primeiro plano, que percorre a tabela inteira, tem um custo estimado em aproximadamente 0,83. Já o segundo plano, que utiliza os operadores Seek e Lookup, tem um custo total estimado em aproximadamente 0,13, o que representa cerca de 15% do primeiro. Naturalmente, você poderá encontrar valores diferentes nos seus testes e, mesmo executando as consultas em uma única máquina, custos e estimativas vão variar ao longo do tempo, fazendo com que o otimizador tome decisões diferentes, de acordo com os dados que fornecidos. Imagine que, durante a vida útil de um banco de dados, as tabelas vão sendo atualizadas e linhas vão sendo inseridas e removidas. A distribuição dos dados pelos volumes de armazenamento dos servidores sofre fragmentações, o que altera, sobremaneira, os custos de E/S associados às leituras e atualizações, da mesma forma que altera também os custos de processamento. Logo, é de se esperar que o otimizador também varie a sua decisão, de acordo com esses parâmetros que vão sendo alterados ao longo do tempo. COMENTÁRIO É por isso que o desempenho das cargas de trabalho tende a variar; é preciso que os profissionais estejam atentos e tomem as ações necessárias para mantê-lo adequado às expectativas de usuários e aplicações. Contudo, resta uma pergunta: quem fornece as informações de custos e estimativas para o otimizador? No primeiro plano, como ele sabe, a priori, que vai encontrar 2.282 linhas que satisfazem a condição estabelecida se ele ainda não percorreu a tabela? No segundo plano, como ele sabe, a priori, que vai encontrar 42 linhas que satisfaçam a condição dada se ele ainda não percorreu o índice? ESTATÍSTICAS As informações que o otimizador tem para analisar planos de execução estão nas estatísticas do banco de dados. O otimizador utiliza as estatísticas coletadas dos objetos para gerar seus planos de execução. O número de linhas em uma tabela e a distribuição dos valores nas colunas da tabela (histograma)são mantidos nessas estatísticas, de forma que o otimizador possa selecionar os operadores mais apropriados para os planos de execução. Vamos observar as estatísticas das tabelas que criamos: O primeiro passo é recuperar o object_id de cada objeto. Para isso, consultamos a tabela sys.objects, que faz parte do catálogo do SQL Server. Com o object_id, podemos consultar a tabela sys.stats, que contém as informações sobre as estatísticas coletadas do objeto. Na imagem a seguir, você pode observar as tabelas que criamos e os valores de object_id correspondentes no resultado do primeiro SELECT. Informações sobre estatísticas de objetos. Captura de tela do software SQL Server Management Studio (SSMS). No segundo SELECT, utilizamos o object_id para recuperar as informações sobre as estatísticas coletadas para todos os objetos associados à tabela CRM.Pessoa, incluindo os índices clusterizado e não clusterizado. COMENTÁRIO Note que cada um deles contém um stats_id, que identifica as estatísticas que foram coletadas para cada um deles. Por meio desse stats_id, podemos recuperar as informações sobre as coletas realizadas. Informações sobre estatísticas de objetos. Captura de tela do software SQL Server Management Studio (SSMS). A sys.stats traz informações muito importantes, como a data da última atualização das estatísticas, o número de linhas da tabela e o número de linhas utilizado para gerar as estatísticas (rows_sampled). COMENTÁRIO Esse resultado nos mostra que as estatísticas estão desatualizadas, pois o número de linhas exibido (1.000) não corresponde ao número de linhas atual da tabela (100.000). Por que isso aconteceu? As estatísticas não são atualizadas a todo momento. Em intervalos regulares, o SQL Server atualiza os dados varrendo um percentual das linhas das tabelas. Os dados coletados são armazenados nas estatísticas e disponibilizados para o otimizador. Quanto mais atualizadas as estatísticas, melhor para o otimizador, pois ele vai utilizar informações mais precisas para selecionar os planos de execução das consultas. Veja, no endereço a seguir, mais detalhes sobre estatísticas do banco de dados: https://docs.microsoft.com/pt-br/sql/relational-databases/statistics/statistics?view=sql-server- ver15 Histograma da chave primária da tabela CRM.Pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Podemos avançar mais na exibição das estatísticas por meio da imagem do comando anterior. Ele mostra o histograma da coluna, isto é, a distribuição dos valores na coluna. No primeiro DBCC, estamos visualizando o histograma da chave primária da tabela CRM.Pessoa, organizado por faixas. javascript:void(0); As faixas são determinadas pelo valor mais alto (RANGE_HI_KEY). Para cada faixa, você pode ver o número de linhas dentro da faixa (RANGE_ROWS) e o número de linhas cujo valor é igual ao valor mais alto da faixa (EQ_ROWS). O histograma possui ainda o número de valores distintos na faixa (DISTINCT_RANGE_ROWS) e o número médio de linhas para cada valor da faixa (AVG_RANGE_ROWS). Na próxima imagem, podemos ver o histograma da coluna data_nascimento. Histograma da coluna data_nascimento da tabela CRM.Pessoa. Captura de tela do software SQL Server Management Studio (SSMS). Pelo histograma da coluna, podemos inferir que há um maior número de valores distintos dentro de cada faixa, quando comparamos com o histograma anterior, exceto pelas datas não geradas automaticamente pelo script que executamos no módulo 2. Também chama a atenção um valor diferenciado para AVG_RANGE_ROWS, resultado do descasamento entre RANGE_ROWS e DISTINCT_RANGE_ROWS, observado nas outras faixas. Isso nos indica que, nessa faixa, existem 2 datas de nascimento iguais. Como apontamos anteriormente, as estatísticas estão desatualizadas. Precisamos atualizá-las e, para isso, vamos utilizar o comando UPDATE STATISTICS. Veja mais detalhes sobre o comando UPDATE STATISTICS no endereço a seguir: https://docs.microsoft.com/pt-br/sql/t-sql/statements/update-statistics-transact-sql?view=sql- server-ver15 javascript:void(0); Geração dos comandos UPDATE STATISTICS. Captura de tela do software SQL Server Management Studio (SSMS). A construção mostrada na imagem anterior percorre as tabelas do catálogo do SQL Server para gerar um comando UPDATE STATISTICS para todas as tabelas presentes no banco de dados. COMENTÁRIO Repare que a cláusula WHERE garante que somente as chaves primárias das tabelas do banco de dados serão selecionadas para a construção dos comandos. Note também que o comando é gerado com a opção FULL SCAN, determinando que todas as linhas da tabela sejam verificadas para a coleta das estatísticas. Para executar a atualização, basta copiar e colar o comando gerado, e, depois, executá-lo. Comando UPDATE STATISTICS com FULL SCAN. Captura de tela do software SQL Server Management Studio (SSMS). Após a execução da atualização, podemos repetir o comando para exibir os dados da coleta. Veja que, agora, esses dados mostram que as 100.000 linhas foram consideradas na coleta. Comando UPDATE STATISTICS com FULL SCAN. Captura de tela do software SQL Server Management Studio (SSMS). ÍNDICES Vimos, no módulo anterior, como criar índices e como eles são importantes para o desempenho das consultas no SQL Server. Os índices podem ser muito benéficos se, de fato, forem utilizados pelo otimizador, especialmente quando criados sobre colunas que tendem a ter seletividade alta para a maior parte dos seus valores. Em contraposição, eles podem ser maléficos se criados em colunas de seletividade baixa. Exemplos clássicos incluem colunas como sexo ou estado_civil. Há poucas opções de valor para essas colunas, de modo que elas terão seletividade baixa e seus índices raramente serão utilizados. Uma questão interessante é: por que seriam maléficos, já que não serão utilizados? Há um custo associado à manutenção do índice. Toda vez que uma atualização é realizada sobre uma tabela, todos os índices podem ser atualizados também. Tipicamente, vamos encontrar tabelas com dezenas de índices não clusterizados, e atualizá-los tem, principalmente, custo de E/S associado. Garantir que os índices existentes estejam, de fato, sendo utilizados é fundamental para o bom desempenho das atualizações no banco de dados, além de evitar desperdício de volume de armazenamento. Ainda que índices ocupem bem menos espaço que as tabelas, você não vai querer uma tabela com 70 índices, sendo que 40 não são utilizados. Veja a seguir como verificar se seus índices estão sendo utilizados. Uso de índices. Captura de tela do software SQL Server Management Studio (SSMS). A consulta mostra, para cada índice da tabela CRM.Pessoa, além do seu tipo e tamanho, o número de Seeks, Scans, Lookups e Updates. Em nosso exemplo, não resta dúvida de que o índice não clusterizado na coluna data_nascimento está servindo ao seu propósito: há um alto número de Seeks e poucos Scans. Já o índice clusterizado contém muitos Lookups e poucos Scans, o que também é um indicador positivo, garantindo planos de execução que não varrem completamente a tabela. ATENÇÃO Caso você encontre, em um relatório desse tipo, índices não clusterizados com poucos Seeks, você deve verificar seu custo de manutenção e considerar sua remoção. Caso encontre índices clusterizados com muitos Scans e poucos Lookups, você deve suspeitar da falta de índices que melhorem os planos de execução gerados pelo otimizador. Veja mais detalhes sobre o uso de índices nos endereços a seguir: https://docs.microsoft .com/pt-br/sql/t-sql/statements/alter-index-transact-sql?view=sql-server- ver15 https://github.com /microsoft/sql-server-samples/tree/master/ samples/databases javascript:void(0); javascript:void(0); Além da questão do uso dos índices, há o problema da fragmentação. Como comentamos anteriormente, durante o ciclo de vida útil de um banco de dados, linhassão inseridas, removidas e atualizadas nas tabelas, e isso provoca as mesmas operações nos índices associados. Quanto maior o volume de atualizações, maior a fragmentação das estruturas de dados, cujas páginas sofrem frequentes splits nas inserções e atualizações. Quanto mais fragmentada estiver uma estrutura, maior o número de páginas necessárias para satisfazer uma consulta e, portanto, maior o seu custo de E/S e menor o seu desempenho. Por isso, como não podemos evitar a fragmentação, devemos monitorá-la e executar as ações apropriadas quando necessário. Vamos checar como está a fragmentação em nossos objetos. Fragmentação de índices. Captura de tela do software SQL Server Management Studio (SSMS). Podemos observar, pelo resultado apresentado, que os índices clusterizados das tabelas têm pouca ou nenhuma fragmentação, mas o índice não clusterizado ind_Pessoa_data_nascimento tem um índice maior que 98%, o que significa que a quase totalidade do índice está fragmentada, ou seja, quase todas as páginas de dados estão em uma ordem diferente da ordenação física da tabela. No SQL Server, as manobras possíveis para resolver esse problema são o REORGANIZE e o REBUILD. No REBUILD, o índice é excluído e criado novamente. Quando isso acontece, garante-se que o percentual de fragmentação vai retornar a zero. No REORGANIZE, o índice não é excluído e a reorganização é realizada por meio de operações como movimentação de linhas e realocação de páginas. Ambas as operações vão impactar as cargas de trabalho; portanto, é importante ter uma janela para realizar a operação. DICA Sugere-se um REORGANIZE para índices de fragmentação pequenos. Para índices maiores, como o que observamos em ind_Pessoa_data_nascimento, é melhor executar um REBUILD. Rebuild de índice. Captura de tela do software SQL Server Management Studio (SSMS). O REBUILD pode ser executado em modo OFF-LINE ou ON-LINE. No modo OFF-LINE, o acesso à tabela correspondente ao índice é bloqueado para que a operação seja executada mais rapidamente. No modo ON-LINE, o acesso continua disponível porque o índice atual permanece operacional enquanto o novo é criado. Após a execução do REBUILD, podemos checar novamente o nível de fragmentação: Fragmentação após Rebuild de índice. Captura de tela do software SQL Server Management Studio (SSMS). A fragmentação retornou de fato a zero; nesse momento, todas as páginas estão ordenadas de acordo com a ordenação física do índice e, portanto, não há fragmentação. Para conhecer todas as opções existentes para REBUILD e REORGANIZE, visite o endereço: https://docs.microsoft.com/pt-br/sql/relational-databases/indexes/reorganize-and-rebuild- indexes?view=sql-server-ver15 Para mais detalhes sobre o comando ALTER INDEX, visite o endereço: https://docs.microsoft.com/pt-br/sql/t-sql/statements/alter-index-transact-sql?view=sql-server- ver15 ATIVIDADE PRÁTICA Verifique o plano de execução da consulta que forma a visão criada na atividade prática do módulo anterior, a CRM.vw_pessoa_documento_endereco. É possível melhorar esse plano e os custos associados a ele? SOLUÇÃO Solução da atividade prática, elaborada por Antony Seabra de Medeiros. Captura de tela do software SQL Server Management Studio (SSMS). O plano de execução apresenta um scan no índice clusterizado da tabela CRM.Pessoa_Endereco, onde é realizado o WHERE na coluna tipo_endereco. Um índice não clusterizado nessa coluna é uma alternativa, caso a seletividade desse predicado seja alta o suficiente para que o otimizador o selecione para o plano. Outras manobras clássicas são a atualização das estatísticas de todas as tabelas envolvidas e a desfragmentação dos índices, caso necessário. javascript:void(0); javascript:void(0); OS PARADIGMAS DE COMUNICAÇÃO EM COMPUTAÇÃO DISTRIBUÍDA No vídeo a seguir, assista a uma demonstração de tuning no SQL Server utilizando estatísticas e índices, um ambiente real e captura dos procedimentos. VERIFICANDO O APRENDIZADO 1. AS ESTATÍSTICAS DE UM BANCO DE DADOS FORNECEM INFORMAÇÕES IMPORTANTES PARA QUE O OTIMIZADOR SELECIONE UM PLANO DE EXECUÇÃO PARA CADA CONSULTA SUBMETIDA A ELE. ENTRE AS INFORMAÇÕES FORNECIDAS PELAS ESTATÍSTICAS, ESTÃO, EXCETO: A) Número de linhas. B) Tamanho médio da linha. C) Distribuição de valores na coluna. D) Última data da coleta. E) Próxima data da coleta. 2. A FRAGMENTAÇÃO DE ÍNDICES PODE DEGRADAR O DESEMPENHO DE SCANS E SEEKS, NA MEDIDA EM QUE AS PÁGINAS DE DADOS FICAM DESORDENADAS NO DISPOSITIVO DE ARMAZENAMENTO. ENTRE AS AÇÕES QUE PODEMOS TOMAR PARA DESFRAGMENTAR UM ÍNDICE, ESTÃO, EXCETO: A) Remover o índice e criá-lo novamente. B) Fazer um refresh. C) Fazer um rebuild on-line. D) Fazer um rebuild off-line. E) Fazer um reorganize. GABARITO 1. As estatísticas de um banco de dados fornecem informações importantes para que o otimizador selecione um plano de execução para cada consulta submetida a ele. Entre as informações fornecidas pelas estatísticas, estão, EXCETO: A alternativa "E " está correta. A próxima data da coleta das estatísticas não é informada; apenas a última data é mostrada quando consultamos a sys.dm_db_stats_properties. 2. A fragmentação de índices pode degradar o desempenho de Scans e Seeks, na medida em que as páginas de dados ficam desordenadas no dispositivo de armazenamento. Entre as ações que podemos tomar para desfragmentar um índice, estão, EXCETO: A alternativa "B " está correta. Não existe uma operação de refresh de índice. O que existe, e pode ser utilizado para desfragmentar um índice, é um rebuild ou um reorganize. CONCLUSÃO CONSIDERAÇÕES FINAIS Neste tema, vimos como os principais objetos de um banco de dados SQL Server podem ser criados e utilizados de acordo com a sua funcionalidade. É fundamental, tanto para o desenvolvedor de sistemas quanto para o administrador de banco de dados, relacionar esses objetos com o seu propósito, de maneira que cada peça do banco de dados possa ser utilizada adequadamente. Casos de uso clássicos foram citados, como o de triggers, para gerar um archive de dados, e o de índices, para melhorar o desempenho de consultas, em uma atividade que chamamos de tuning. Estamos certos de que os módulos do presente conteúdo foram proveitosos, principalmente com o uso dos scripts disponibilizados. Experimentar as manobras e observar os resultados é a melhor maneira de avançar na construção do conhecimento, especialmente quando os conceitos e as técnicas, como as apresentados para o SQL Server, dependem muito do ambiente de execução. O uso de estatísticas, sua atualização e o impacto que um índice tem nas decisões do otimizador só podem ser compreendidos se você experimentar suas diversas facetas, usando a sua própria instância de SQL Server. AVALIAÇÃO DO TEMA: REFERÊNCIAS ASSAF, W.; WEST, R.; AELTERMAN, S.; CURNUTT, M. SQL Server 2017 Administration Inside Out. 1 ed. Microsoft Press, 2017. DELANEY, K.; FREEMAN, C. Microsoft SQL Server 2012 Internals. 1 ed. Microsoft Press, 2012. RAMAKRISHNAN, R.; GEHRKE, J. Database Management Systems. 3. ed. Nova York: McGraw Hill, 2002. EXPLORE+ Explore o GitHub da Microsoft, no site da Microsoft SQL ‒ Documentação. Lá, você vai encontrar scripts de instalação de bancos de dados, como o adventure-works e o wide-world- importers, clássicos do mundo SQL Server. Implante o último em sua instância. Ele contém estruturas e procedimentos preparados para mostrar tanto cargas transacionais quanto analíticas, sendo possível acompanhar a criação de todos os tipos de objetos estudados neste conteúdo. Além da criação e manutenção dos objetos, as consultas preparadas para o banco de dados contêm planos de execução diversos. Você vai poder verificá-los e propor ajustes de tuning, com atualização das estatísticas do banco de dados e a criação de índices não clusterizados, caso necessário. Experimente! Certamente, você vai avançar nos seus conhecimentos ao observar como a própriaMicrosoft estruturou o banco de dados mais estudado na atualidade por profissionais especializados em SQL Server. CONTEUDISTA Antony Seabra de Medeiros
Compartilhar