SQL Server: Além do Conceito Blog Post Collection MVTech |1 SQL Server: Além do Conceito Blog Post Collection MVTech |2 SQL Server: Além do Conceito Blog Post Collection SQL Server: Além do Conceito Blog Post Collection Diego Nogare – Edvaldo Castro – Demetrio Silva – Marcel Inowe – Marcos Freccia – Ivan Lima – Fabiano Amorim – Sulamita Dantas – Marcelo Fernandes – Cibelle Castro – Leandro Ribeiro – Luciano Moreira – Nilton Pinheiro – Tiago Balabuch – Felipe Ferreira MVTech |3 SQL Server: Além do Conceito Blog Post Collection MVTech |4 SQL Server: Além do Conceito Blog Post Collection SQL Server: Além do Conceito Blog Post Collection Uma coletânea de posts escolhidos pelos próprios autores para te ajudar nas atividades do dia-a-dia. MVTech |5 SQL Server: Além do Conceito Blog Post Collection Editor: Diego Nogare Introdução: Edvaldo Castro Prefácio: Roberto Fonseca Capa: Felipe Borges Autores: Diego Nogare – Edvaldo Castro – Demetrio Silva – Marcel Inowe – Marcos Freccia – Ivan Lima – Fabiano Amorim – Sulamita Dantas – Marcelo Fernandes – Cibelle Castro – Leandro Ribeiro – Luciano Moreira – Nilton Pinheiro – Tiago Balabuch – Felipe Ferreira MVTech |6 SQL Server: Além do Conceito Blog Post Collection Introdução Estar envolvido em uma comunidade é sempre mais importante e proveitoso de que viver de um modo isolado, seja nos âmbitos pessoais, profissionais e quaisquer outros. A comunidade técnica de profissionais que trabalham com produtos e ferramentas ligados à Plataforma de Dados da Microsoft é bem atuante e unida, isso faz com que muito conteúdo seja gerado, seja com vídeos, eventos, palestras, entrevistas e postagens em blogs. Com esta grande quantidade de material correlacionado, um grupo de amigos que aqui denominados "SQL Friends" teve a ideia de reunir seus trabalhos em blogs pessoais para criar uma coletânea destes posts e entregar em uma única publicação alguns textos de seus blogs. Os assuntos estão direcionados ao que os autores escrevem geralmente em seus blogs pessoais, podendo ou não estarem correlacionados entre si. O mais interessante, é que em uma mesma publicação, encontra-se um rico e variado conteúdo: Administração de Banco de Dados, BI, Performance dentre outros. “SQL Server: Além do Conceito - Blog Post Collection" foi idealizado para proporcionar uma experiência variada e com conteúdo idem, por isso aprecie o conteúdo e se tiver alguma dúvida ou sugestão, fique à vontade para entrar em contato direto com o autor, através do blog do mesmo que está informado no interior desta publicação. Um ponto importante a ser mencionado, este trabalho por ser voluntário e não ter um cunho com fins financeiros, teve uma tratativa diferente mas não menos cuidadosa com relação à um livro ordinário. Cada autor é o responsável direto pelo que escreveu e publicou na coletânea, mas todos estão juntos para proporcionar e compartilhar o conhecimento que adquiriram ao longo de vários anos de experiência. MVTech |7 SQL Server: Além do Conceito Blog Post Collection Apesar de NÃO ser um LIVRO formalmente falando, é possível absorver conhecimento técnico de alta qualidade escrito pelos autores, exatamente como pode ser encontrado em seus respectivos blogs. Aproveite bem, e quaisquer necessidades de contato, não hesite em nos enviar uma mensagem. Boa Leitura, Edvaldo Castro MVTech |8 SQL Server: Além do Conceito Blog Post Collection Prefácio A presente obra foi cuidadosamente produzida como fruto de diversos anos de trabalho e conhecimento dos autores e corresponde a uma compilação aprimorada de posts publicados por eles no decorrer dos últimos meses e extensivamente testado como parte dos seus esforços em adquirir um conhecimento avançado e aprofundado. O Microsoft SQL Server 2014 é a próxima geração da Plataforma de Informação da Microsoft, com novas funcionalidades que entregam um melhor desempenho, expandem seus dados para a nuvem e provêem estruturas de BI poderosas. O SQL Server 2014 possui dezenas de novas funcionalidades e melhorias para DBAs, Desenvolvedores e especialistas em Business Intelligence. O material aqui apresentado tem como finalidade principal servir como base de pesquisa para aqueles que têm interesse em entender sobre novas funcionalidades e evoluir os seus conhecimentos. Neste livro, você verá como o SQL Server 2014 utiliza funcionalidades como o Read Committed Snapshot Isolation, Particionamento de Tabelas, Tuning no Sharepoint e SQL Server, Importação de Dados com o Integration Services, Auditoria no SQL Server, Erros de Instalação, Fragmentação do Transaction Log, uso de Snapshots, Deadlocks, conversões e uso de tipos de dados de Datas, Contadores de Performance e problemas de rede para entregar uma das melhores ferramentas para a tomada de decisão e gerenciamento de bancos de dados disponíveis no mercado. Temos a certeza que esta obra irá contribuir consideravelmente para a desmistificação de muitos tópicos considerados complexos, mostrando não apenas o significado destes tópicos, mas também mostrando o caminho a seguir para a utilização no dia-a-dia. MVTech |9 SQL Server: Além do Conceito Blog Post Collection Desejamos a todos que tirem o melhor proveito deste excelente trabalho e pedimos que nos informem quaisquer imprecisões ou incorreções que possam ser encontradas nesta obra através do email [email protected], para que possamos sempre manter disponível um texto útil e eficaz para o seu aprendizado. Roberto Fonseca M V T e c h | 10 SQL Server: Além do Conceito Blog Post Collection MVTech O Minha Vida (http://www.minhavida.com.br) é uma empresa com um grande propósito: melhorar a qualidade de vida da população. Queremos ser capazes de despertar nas pessoas o cuidado com a sua própria saúde. E quando falamos em saúde, nos referimos não só à prevenção ou ao tratamento de doenças, mas também a pequenas mudanças de hábitos capazes de transformar positivamente o dia a dia das pessoas. Queremos fazer diferença na vida das pessoas! Pensando nisso, nosso time de tecnologia criou o MVTech, uma iniciativa para disseminar conhecimento através de iniciativas de seus colaboradores, buscando o aprimoramento do mercado nacional. Com diversas ações como: artigos técnicos em blogs; matérias para portais; respostas em foruns de discussão, palestras em eventos, eventos presenciais e online, etc… afinal, somos apaixonados pelo que fazemos! por que não compartilhar nossa paixão? A criação do MVTech dá um passo adiante nesta linha de compartilhamento de conhecimento, passando a existir um canal oficial onde poderão ser encontrados grandes conteúdos. Seja bem vindo ao MVTech Alexandre Tarifa – Diretor de Tecnologia – Minha Vida M V T e c h | 11 SQL Server: Além do Conceito Blog Post Collection M V T e c h | 12 SQL Server: Além do Conceito Blog Post Collection Sumário EDVALDO CASTRO ............................................................................... 21 DBA por acidente X Command Line ...................................................................... 21 “DBA por acidente” ........................................................................................... 21 READ COMMITTED SNAPSHOT ISOLATION – Aprecie com moderação ................ 24 “RCSI – Aprecie com moderação” ...................................................................... 24 MUITO BOM...................................................................................................... 24 CENÁRIO 1 ........................................................................................................... 25 RCSI NO CASO DO SR. JOAQUIM ............................................................................... 25 MAS…................................................................................................................ 26 CENÁRIO 2 ........................................................................................................... 27 O PROBLEMA........................................................................................................ 27 RCSI NESTE CASO .................................................................................................. 27 RESUMINDO:..................................................................................................... 32 PRÓS E CONTRAS DO RCSI: ...................................................................................... 32 REFERÊNCIAS .................................................................................................... 33 Artigos técnicos: O guia definitivo (ou não) .......................................................... 34 MOTIVAÇÃO ......................................................................................................... 34 RISCOS E OPORTUNIDADES....................................................................................... 34 QUANDO COMEÇAR? ............................................................................................. 35 PESQUISE ............................................................................................................. 35 LEIA E ESTUDE MUITO ............................................................................................. 35 FAÇA CITAÇÕES E REFERÊNCIAS .................................................................................. 36 REVISÃO PERIÓDICA (NÃO OBRIGATÓRIA) .................................................................... 36 O ARTIGO TÉCNICO ........................................................................................... 37 TIPOS DE ARTIGOS TÉCNICOS ............................................................................ 37 DOCUMENTAÇÃO................................................................................................... 37 HOW TO(S) .......................................................................................................... 37 BENCHMARKS E EXPERIÊNCIAS .................................................................................. 37 O ARTIGO TÉCNICO EM SI.................................................................................. 38 ESTRUTURA .......................................................................................................... 38 LINGUAGEM ......................................................................................................... 38 PÚBLICO ALVO ...................................................................................................... 38 GRAMÁTICA ...................................................................................................... 39 M V T e c h | 13 SQL Server: Além do Conceito Blog Post Collection EVITE OS ERROS MAIS COMUNS (DIGITAÇÃO, GÍRIAS, CONCORDÂNCIA, ETC) ......................... 39 SOLICITE REVISÕES (AMIGOS, COMUNIDADE, PARENTES, SR. JOAQUIM) ............................ 39 PRINCIPAIS PREOCUPAÇÕES .............................................................................. 40 SEMPRE ............................................................................................................... 40 NUNCA................................................................................................................ 40 PUBLICIDADE ........................................................................................................ 40 FAÇA BARULHO ................................................................................................. 41 CONCLUSÃO ...................................................................................................... 41 DIEGO NOGARE................................................................................... 42 Partition Table ...................................................................................................... 42 Particionamento de Tabelas .............................................................................. 42 CENÁRIOS/BENEFÍCIOS ............................................................................................ 44 DEFINIÇÕES/TERMINOLOGIAS ................................................................................... 45 CRIANDO FILEGROUP .............................................................................................. 48 CRIANDO PARTITION FUNCTION ................................................................................ 54 CRIANDO O PARTITION SCHEME ................................................................................ 56 CRIANDO A TABELA................................................................................................. 57 COMPARATIVO DE INSERÇÃO DE DADOS EM UMA TABELA COM COLUMNSTORE INDEX NO SQL SERVER 2012 ....................................................................................................... 58 DEMETRIO SILVA ................................................................................. 73 Tuning no SharePoint e SQL Server com o Developer Dashboard ........................ 73 Tunin no SharePoint com Developer Dashboard ............................................... 73 INTRODUÇÃO .................................................................................................... 73 CONFIGURAÇÃO .................................................................................................... 74 Veja a execução do script na figura 3: ............................................................... 76 Visualizando o Developer Dashboard ................................................................ 76 CONCLUSÃO ...................................................................................................... 80 Acessando dados do SharePoint com PowerPivot ................................................ 82 INTRODUÇÃO .................................................................................................... 82 REQUISITOS .......................................................................................................... 82 COMO FUNCIONA .................................................................................................. 82 IMPORTAR PARA O POWERPIVOT NO EXCEL ................................................................. 85 CONCLUSÃO ...................................................................................................... 91 Configurar envio de e-mail no SharePoint / SQL Server com o GMAIL ................. 92 M V T e c h | 14 SQL Server: Além do Conceito Blog Post Collection PASSO 1: CONFIGURAR O SMTP SERVER NO WINDOWS 2008 ........................................ 92 MARCEL INOWE ................................................................................ 101 Dicas sobre o banco de dados do Protheus(Totvs) ............................................. 101 VAMOS AS DICAS: ................................................................................................ 101 MARCOS FRECCIA ............................................................................. 105 Importando arquivos excel usando o SSIS .......................................................... 105 T-SQL no SQL Server 2012 – Parte 1 .................................................................... 113 1) EXECUTE WITH RESULT SETS ....................................................................... 113 VAMOS VER COMO FUNCIONA? ............................................................................... 113 2) SEQUENCE .................................................................................................. 115 COMO UTILIZAR? ................................................................................................. 116 PASSO 1: CRIAÇÃO DA SEQUENCE. ........................................................................... 116 COMO UTILIZAMOS A SEQUENCE? ............................................................................ 116 RESULTADO. ....................................................................................................... 118 T-SQL no SQL Server 2012 – Parte 2 – Paginação de dados ................................ 120 CONSULTA 1 ....................................................................................................... 121 CONSULTA 2 ....................................................................................................... 122 IVAN LIMA ......................................................................................... 124 Inside The Machine – Introdução ....................................................................... 124 VELOCIDADE DO PROCESSADOR É TUDO? ................................................................... 124 REFERÊNCIAS: ................................................................................................. 128 Inside the Machine – Processadores................................................................... 129 INTRODUÇÃO .................................................................................................. 129 PROCESSADORES ................................................................................................. 129 OVERVIEW DA MICROARQUITETURA......................................................................... 129 CORE E UNCORE .................................................................................................. 130 PLANTA ............................................................................................................. 130 XEON E7 ........................................................................................................... 131 CORE I5 460M ................................................................................................... 132 MOORE’S LAW .................................................................................................... 133 M V T e c h | 15 SQL Server: Além do Conceito Blog Post Collection COMPLEXIDADE ................................................................................................... 135 GPGPU ............................................................................................................ 135 CACHE............................................................................................................... 135 REFERÊNCIAS .................................................................................................. 135 Inside The Machine - Hyper-Threading (SMT) e SQL Server ................................ 137 TEORIA E PRÁTICA ................................................................................................ 138 MITO ................................................................................................................ 138 PROCESSADORES ................................................................................................. 138 REFERÊNCIAS: ................................................................................................. 139 FABIANO NEVES AMORIM................................................................. 140 Join reordering e Bushy Plans ............................................................................. 140 INTRODUÇÃO .................................................................................................. 140 JOIN REORDERING E BUSHYPLANS ............................................................................ 140 BUSHY PLANS NO SQL SERVER ............................................................................... 141 STATISTICS IO: ................................................................................................. 144 PLANO ESTIMADO: ............................................................................................... 145 STATISTICS IO: ................................................................................................. 149 STATISTICS IO: ................................................................................................. 150 STATISTICS IO: ................................................................................................. 152 STATISTICS IO: ................................................................................................. 153 CONCLUSÃO .................................................................................................... 154 NOTA IMPORTANTE: ............................................................................................. 154 REFERÊNCIAS .................................................................................................. 154 SULAMITA DANTAS ........................................................................... 155 Policy Based Management ................................................................................. 155 MARCELO FERNANDES ...................................................................... 162 Solucionando Problemas: Error Failed to open loopback connection ao executar SP_READERRORLOG ........................................................................................... 162 INTRODUÇÃO .................................................................................................. 162 SINTOMA ........................................................................................................... 162 CAUSA .............................................................................................................. 162 SOLUÇÃO ........................................................................................................... 163 M V T e c h | 16 SQL Server: Além do Conceito Blog Post Collection LEITURAS ADICIONAIS ............................................................................................ 164 Error to install SQL Server 2008 on Windows 2012............................................. 165 Token Bloat - Cannot generate SSPI context....................................................... 171 PROBLEMA ......................................................................................................... 171 COMO RESOLVER ................................................................................................. 176 EM CADA ESTAÇÃO ............................................................................................... 176 LEITURAS ADICIONAIS ..................................................................................... 177 CIBELLE CASTRO ................................................................................ 178 Auditoria ............................................................................................................. 178 Descobrindo Auditoria no SQL Server 2008 ..................................................... 178 POR QUE UTILIZAR AUDITORIA? ............................................................................... 178 PODE SER FEITO ATRAVÉS DE SCRIPTS........................................................................ 179 NOTA 01: .......................................................................................................... 179 COMO O SQL SERVER AUDIT TRABALHA? .................................................................. 179 NOTA 02: .......................................................................................................... 181 NOTA 03: .......................................................................................................... 184 DATABASE AUDIT SPECIFICATIONS .................................................................. 184 NOTA 03: .......................................................................................................... 186 PASSA A PASSO DE COMO CRIAR UMA AUDITORIA........................................................ 187 FAREMOS ESSAS CONFIGURAÇÕES DO SERVER AUDIT ATRAVÉS DE TSQL E O MANAGEMENT STUDIO.............................................................................................................. 193 CRIANDO UM SERVER OU SERVER AUDIT SPECIFICATION. .............................................. 200 CRIANDO UM SERVER OU DATABASE AUDIT SPECIFICATION. .......................................... 206 CONCLUSÃO .................................................................................................... 213 REFERÊNCIAS .................................................................................................. 213 Performance e Desempenho .............................................................................. 215 System Monitor & SQL Profiler ........................................................................ 215 O QUE É O SYSTEM MONITOR? ............................................................................... 215 NOTA 1: ............................................................................................................ 215 NOTA 2 ............................................................................................................. 217 COMO CRIAR UM DATA COLLETOR SETS? .................................................................. 218 PARA CRIAR UM DATA COLLETOR SETS PERSONALIZADO, SIGA OS PASSOS ABAIXO: .............. 218 SQL SERVER PROFILER ..................................................................................... 225 O QUE É O TRACE? ............................................................................................... 225 NOTA 4: ............................................................................................................ 228 M V T e c h | 17 SQL Server: Além do Conceito Blog Post Collection COMO APLICAR FILTROS NO SQL PROFILER? .............................................................. 230 PERFORMANCE X MONITORAMENTO ....................................................................... 231 DICA: ................................................................................................................ 231 CRIANDO TRACES ................................................................................................. 231 DICA *: ............................................................................................................. 239 CONCLUSÃO .................................................................................................... 239 REFERÊNCIAS .................................................................................................. 239 Restore Database com SSIS ................................................................................ 241 FTP COM WINSCP .............................................................................................. 242 EXECUTE PROCESS TASK ........................................................................................ 244 CRIAÇÃO VARIÁVEIS NO SSIS .................................................................................. 247 FOREACH LOOP CONTAINER ................................................................................... 248 EXECUTE SQL TASK (DELETE DATABASE) .............................................................. 250 EXECUTE SQL TASK (RESTORE DATABASE / USER PERMISSION) ............................ 253 EXECUTE PROCESS TASK (MODIFY NAME FTP FILE) ................................................ 255 LEANDRO RIBEIRO ............................................................................. 256 Fragmentação do Transaction Log - Parte I......................................................... 256 INTRODUÇÃO .................................................................................................. 256 TRANSACTION LOG ............................................................................................... 257 Fragmentação do Transaction Log - Parte II........................................................ 260 DICA: ................................................................................................................ 264 VAMOS TESTAR! .................................................................................................. 267 INFORMAÇÃO ADICIONAL ....................................................................................... 271 MELHORES PRÁTICAS: ........................................................................................... 271 LUCIANO MOREIRA ........................................................................... 273 O caso dos snapshots e data cache thrashing ..................................................... 273 DATA CACHE E O DATABASE SNAPSHOT. ......................................................... 273 SCRIPT 1 – CRIAÇÃO DOS BANCOS DE DADOS .............................................................. 273 SCRIPT 3 – RESULTADO DE IO PARA AS CONSULTAS ...................................................... 275 SCRIPT 4 – CONSULTANDO O DATA CACHE ................................................................. 275 DATA CACHE THRASHING ................................................................................ 276 SCRIPT 5 – CRIANDO DIVERSOS SNAPSHOTS E MAX SERVER MEMORY ................................ 276 SCRIPT 6 – UTILIZANDO O ESPAÇO DO DATA CACHE ...................................................... 277 SCRIPT 7 – DATA CACHE THRASHING ........................................................................ 278 M V T e c h | 18 SQL Server: Além do Conceito Blog Post Collection Trigger causando deadlocks................................................................................ 279 PERGUNTA: INDEXAÇÃO PODE ELIMINAR PROBLEMAS DE DEADLOCKS? .............................. 279 ENTÃO PERGUNTO: AONDE ESTÁ O DEADLOCK? ........................................................... 280 ENCONTRANDO O DEADLOCK .................................................................................. 280 MINIMIZANDO OS DEADLOCKS ................................................................................ 282 RESOLVENDO O PROBLEMA (DE VERDADE) ................................................................. 284 CONCLUSÃO .................................................................................................... 285 VARCHAR(MAX) vs. TEXT (Sintaxe?) ................................................................... 287 SCRIPT 01 – DUAS TABELAS IDÊNTICAS, VARCHAR(MAX) E TEXT ................................ 287 SCRIPT 02 – ANALISANDO AS UNIDADES DE ALOCAÇÃO ................................................. 289 SCRIPT 03 – SP_TABLEOPTION PARA LARGE VALUES ..................................................... 289 NILTON PINHEIRO ............................................................................. 293 Trabalhando com datas e conversões no SQL Server ......................................... 293 OS TIPOS DE DADOS DATETIME E SMALLDATETIME ..................................................... 293 ENTENDENDO O ARMAZENAMENTO DOS VALORES DATA E HORA...................................... 294 TRABALHANDO COM A PARTE DATA .......................................................................... 296 LISTAGEM 1. SCRIPT PARA CRIAÇÃO E POPULAÇÃO DA TABELA DE PEDIDOS ........................ 297 FUNÇÕES E CONVERSÕES ....................................................................................... 299 TRABALHANDO COM A PARTE HORA ......................................................................... 302 CONCLUSÃO .................................................................................................... 305 Monitorando alterações de Dados com a Cláusula OUTPUT .............................. 306 DICAS PARA A UTILIZAÇÃO DO OUTPUT ................................................................... 311 TIAGO BALABUCH ............................................................................. 313 PERFORMANCE COUNTER - SUBSISTEMA DE DISCOS ......................................... 313 UTILIZAÇÃO DE DISCO ........................................................................................... 313 OS CONTADORES UTILIZADOS PARA MEDIR AS INFORMAÇÕES SÃO: ................................... 313 TEMPO DE RESPOSTA ............................................................................................ 314 REFERÊNCIAS: ................................................................................................. 315 PROBLEMAS DE REDE – ASYNC_NETWORK_IO ................................................... 316 OBJETIVO ........................................................................................................... 316 ANÁLISE INICIAL – BANCO DE DADOS: ...................................................................... 316 ANÁLISE INICIAL – WEB: ....................................................................................... 317 ANÁLISE DETALHADA ............................................................................................ 318 M V T e c h | 19 SQL Server: Além do Conceito Blog Post Collection OS CONTADORES UTILIZADOS FORAM:....................................................................... 318 AMBIENTE DE BANCO DE DADOS .................................................................... 319 AMBIENTE WEB............................................................................................... 322 RESOLUÇÃO ........................................................................................................ 323 CONCLUSÃO .................................................................................................... 323 REFERÊNCIAS: ................................................................................................. 324 Suspect database - MSDTC in-doubt transaction ................................................ 325 PROBLEMA ...................................................................................................... 325 RESOLUÇÃO .................................................................................................... 326 CONCLUSÃO .................................................................................................... 327 REFERÊNCIAS: ..................................................................................................... 328 FELIPE FERREIRA ............................................................................... 329 A carreira de DBA está morrendo? ..................................................................... 329 NO MERCADO DE HOJE NÓS TEMOS DOIS PROBLEMAS MUITO COMUNS: ............................ 329 Criando um datawarehouse para testes ............................................................. 331 PASSO 1: ........................................................................................................... 331 PASSO 2: ........................................................................................................... 332 PASSO 3: ........................................................................................................... 333 PASSO 4: ........................................................................................................... 334 M V T e c h | 20 SQL Server: Além do Conceito Blog Post Collection Edvaldo Castro www.edvaldocastro.com DBA por acidente X Command Line “DBA por acidente” Começo o texto de hoje falando um pouco deste que é um termo muito comum em rodas de conversas de DBAs e profissionais que se dedicam a fazer bem feito e com excelência aquilo que se propõe a fazer, neste caso mais especificamente falando, ser um DBA cada vez melhor… Abro aqui um parêntese para indicação de leitura – “How to become an exceptional DBA”. O “DBA por acidente”, as vezes nem mesmo sabe que é um DBA, a ele são atribuídas atividades de um DBA em paralelo às suas obrigações e quando menos se dá conta, já está atuando única e exclusivamente com a Administração do SGBD (Aqui, leia-se SQL Server). Pelo fato de o SQL Server, diferente da maioria dos demais SGBDs, ter uma interface amigável e bastante intuitiva, muitos dos DBAs do tipo supracitado, ao executarem tarefas cotidianas e relativamente simples do dia-a-dia (tais como: backup, restore, criação de base nova, etc), simplesmente se acomodam e deixam de buscar conhecimento e entendimento a fundo do funcionamento da ferramenta, de possíveis problemas e soluções para poder atuar de forma mais rápida e efetiva. Em outros SGBDs, como por exemplo: Oracle e DB2, a administração da ferramenta geralmente é de certa forma mais complexa e requer maior conhecimentos das particularidades destas, e talvez por este motivo, seja muito mais comum a existência de “DBAs por acidente” no mundo SQL Server. Ainda que o Microsoft SQL Server ofereça uma interface super amigável e fácil de trabalhar, uma boa forma de se livrar das armadilhas do vício na interface gráfica que “facilita” muito a vida do DBA, é começar a olhar como as coisas funcionam em background. Por exemplo, ao executar um backup simples de uma base de dados via SSMS (SQL Server Management Studio), M V T e c h | 21 SQL Server: Além do Conceito Blog Post Collection porque não gerar um script da execução deste backup e das próximas vezes que se for executar um backup simples, fazê-lo via T-SQL apenas alterando o script previamente gerado? Com o tempo, naturalmente este comando de backup será memorizado e não haverá mais a necessidade da dependência da interface para execução desta atividade… Um dos pontos, é o conhecimento dos códigos gerados por tras de cada instrução submetida via interface gráfica, mas o estudo e conhecimento daquilo que se faz (neste caso, Administrar Banco de Dados (SQL Server)), vai muito além disto. Neste post, estou dando ênfase à utilização de códigos nas atividades do dia-a-dia de um DBA, pois acredito ser este um grande passo para se deixar o rótulo de “DBA por acidente” para se tornar um profissional cada vez melhor e saber exatamente aquilo que se está fazendo… Posso citar inúmeras vantagens, na utilização de códigos de comando ao invés de interfaces gráficas, mas em minha opinião, destacam-se os seguintes fatores: Produtividade: Particularmente depois que se adquire prática, é muito mais rápido criar um usuário, executar um backup ou restore via T-SQL do que efetuar diversos cliques na tela, para realizar estas tarefas. Escalabilidade: Para fazer uma operação de backup/restore, pode ser pequena a diferença de tempo gasto usando tanto interface quanto T-SQL, porém tente fazer uma operação destas com dezenas ou até mesmo centenas de bases (e acredite, existem muitos cenários para isto). Flexibilidade: Se você é um DBA que usa única e exclusivamente a interface gráfica do SSMS e mal sabe como as coisas acontecem nos códigos executados por suas “telinhas”, é bem possível que suas mãos ficarão literalmente atadas caso você se depare com um servidor onde o SQL Server esteja devidamente instalado, mas não haja o SSMS. Caso você não seja totalmente dependente da ferramenta gráfica, você poderá (em casos extremos) trabalhar normalmente conectando-se via SQLCMD. Além dos três fatores supracitados, existem outros diversos, porém não é a intenção ficar enumerando o que considero melhor ou pior em cada um dos meios de administração do SQL Server. M V T e c h | 22 SQL Server: Além do Conceito Blog Post Collection Na minha visão a relação existente entre um DBA por acidente e Linhas de código, é que normalmente DBAs por acidente não se preocupam em entender como a coisa funciona, e por isto, geralmente continuam a sempre fazer a mesma tarefa, da mesma maneira, enquanto aqueles que se propõe a ser excelentes profissionais, sempre estão correndo atras de entendimento e fugindo das limitações impostas (neste caso, falando sobre utilizar única e exclusivamente, Interface Gráfica). Sinceramente, não tenho nada contra quem utiliza interface gráfica, desde que o faça por preferência, e não por limitação de não saber fazer de outra maneira. É fato que ninguém nasce sabendo, ou com Master degree em nada, mas nunca é tarde para começar a correr atras do prejuízo… A intenção do texto realmente não foi em ser técnico, apenas externar algo que penso com relação ao assunto que se faz presente nos meios profissionais… Grande abraço, Edvaldo Castro http://edvaldocastro.com M V T e c h | 23 SQL Server: Além do Conceito Blog Post Collection READ COMMITTED SNAPSHOT ISOLATION – Aprecie com moderação “RCSI – Aprecie com moderação” “Não existe almoço grátis” “Muito cuidado com as armadilhas do RCSI” O início proposital deste post é para demonstrar alguns dos benefícios e também os pontos de atenção com a possibilidade da alteração do comportamento padrão de uma base de dados no SQL Server, quando se trata de concorrência e isolamento das transações. Por padrão, o SQL Server tem um comportamento “Pessimista”, onde o nível de isolamento padrão é o “Read Committed”, o que basicamente faz com que o SQL Server tenha um número maior de locks, reduzindo a concorrência entre as transações. Acesse (https://msdn.microsoft.com/enus/library/ms189122(v=sql.105).aspx) para um overview nos Níveis de Isolamento no SQL Server. MUITO BOM Resumidamente, o Read Committed Snapshot Isolation (RCSI), trabalha com o versionamento de registros, utilizando-se da tempdb para tal, fazendo com que o comportamento “Pessimista” do nível de isolamento “Read Committed” onde Leitores (Select) bloqueiam Escritores (Insert, Update e Delete), e vice-versa, seja substituído por padrão na base em que foi ativado o RCSI para o comportamento “Otimista”, onde Leitores (Select) e Escritores (Insert, Update, Delete) não se bloqueiam. M V T e c h | 24 SQL Server: Além do Conceito Blog Post Collection Quando há concorrência entre um Updates e Selects submetidos a um mesmo registro, é gerado uma versão comitada do registro, que então esta é lida da pela transação que entrou em segundo lugar. Esta alteração do corportamento Pessimista para Otimista, pela habilitação do RCSI não acaba com bloqueios entre escritores (update x update) e também não evita bloqueios onde há verificação de constraints (foreign Keys, por exemplo). Quando leva-se em consideração o Read Committed Snapshot Isolation Level apenas até os pontos aqui exibidos, não há mais o que se pensar, pode se ter a falsa ideia de solução para todos os problemas de concorrência e bloqueios e a ideia de ativá-lo imediatamente em todas as bases SQL Server da instância é demasiadamente tentadora. Para Exemplificar melhor, segue uma citação de quando o problema é solucionado habilitando-se o RCSI. C ENÁRIO 1 Na padaria do Sr. Joaquim, são produzidos 1.000.000 de pães por dia, e o sistema de panificação automaticamente faz um update na tabela de pães produzidos naquele dia. Esporadicamente o Sr. Joaquim gosta de tirar relatórios para saber a quantidade produzida até então, porém, seus relatórios ficam bloqueados por muito tempo, visto que os updates são constantes e demorados. RCSI NO CASO DO S R . J OAQUIM Neste caso específico, a habilitação do RCSI pode minimizar drasticamente os problemas do Sr. Joaquim com a lentidão de seus relatórios, uma vez que seus “selects” não mais esperarão pelos “updates” automáticos realizados pelo moderno sistema de fabricação de pães. Os updates continuam sendo realizados com a mesma frequência, e apenas bloqueando-se entre si quando necessários (lembrando que o RCSI não evita bloqueios entre updates), e quando o Sr. Joaquim submeter um select M V T e c h | 25 SQL Server: Além do Conceito Blog Post Collection envolvendo os registros bloqueados, ele receberá o resultados dos últimos comitados e não serão considerados aqueles com transações em aberto. MAS… Porém, como mencionado no início deste post… “Não existe almoço grátis”… “Muito cuidado com as armadilhas do RCSI”… Adiciono mais uma… “Coisas estranhas podem acontecer” Não são raras as vezes em que os bloqueios e esperas são benéficos e necessários, para se evitar erros de negócios ou até mesmo inconsistências no valor dos dados de sua base. O Read Committed Snapshot Isolation, é uma excelente opção, fantástica e que é passível sim, de ser habilitada na maioria das bases de dados da maioria dos ambientes com SQL Server, porém é necessário um levantamento cauteloso dos pontos onde podem incorrer problemas pela habilitação deste “comportamento” de uma base de dados do SQL Server. Um dos maiores pontos de atenção é que o RCSI é habilitado para a base inteira, fazendo com que o nível de isolamento das transações para esta base, seja por padrão alterado. Para que se tenha níveis de isolamento diferentes, é necessário que estes sejam informados dentro das transações submetidas. M V T e c h | 26 SQL Server: Além do Conceito Blog Post Collection Vale ressaltar que apesar dos cuidados, custos e advertências supracitados, normalmente a relação CUSTO X BENEFÍCIO vale a pena e os problemas em potencial são poucos, em relação aos benefícios com o uso do RCSI. Para facilitar um pouco o entendimento, segue uma descrição de um caso onde o RCSI pode causar um grande problema. C ENÁRIO 2 Uma empresa tem um programa conjunto entre as áreas Financeira e RH, de empréstimo de dinheiro da própria empresa a seus empregados, com desconto em folha de pagamento. As regras para que o colaborador possa pegar dinheiro, são bem simplistas e a principal delas, é que o e mesmo esteja empregado. O P ROBLEMA João Castro, trabalhou por 10 anos na empresa referida, e um belo dia foi chamado pelo RH que lhe agradeceu pelos serviços e o demitiu. Sabendo João que a empresa tinha o programa de empréstimos e que o Depto Financeiro era logo na sala ao lado, passou diretamente no financeiro e pegou 20 mil reais que foi prontamente liberado. João acabava de ser demitido e receber 20 mil reais em empréstimo, que não pagaria nunca, visto que não teria mais vínculo com a empresa. RCSI NESTE CASO Supondo que existam 2 Tabelas envolvidas no processo: TB_PESSOA TB_EMPRESTIMO O processo de empréstimo verifica se a pessoa está empregada ou não (TB_PESSOA) para liberar o dinheiro (TB_EMPRESTO). Hipoteticamente falando, João por demitido por alguém do RH que abriu o sistema para atualizar o status para “DEMITIDO”, mas antes de executar M V T e c h | 27 SQL Server: Além do Conceito Blog Post Collection o commit da transação, resolveu ir tomar um café e a deixou aberta. João foi ao Depto Financeiro, alguém deste departamento abriu uma transação para liberar empréstimo, foi consultar na tabela TB_PESSOA se João estava empregado e recebeu como resultado “EMPREGADO”, visto que uma transação de update já estava aberta, porém não havia sido comitada. Quando o alguém do RH voltou, salvou via sistema a demissão de João, alterando seu status para “DEMITIDO”, porém o campo SITUACAO_EMPRESTIMO na tabela TB_EMPRESTIMO estava como “LIBERADO”. Neste caso específico, o bloqueio deveria acontecer e a transação de liberação do empréstimo obrigatoriamente deveria ser bloqueada pela alteração na tabela que informa se a pessoa está empregada ou não. Ainda assim, este não seria um empecilho para a habilitação do RCSI na base, visto que é possível forçar com um HINT que a espera aconteça. Foram criados Scripts para demonstração do caso citado que podem ser baixados pelo endereço: http://edvaldocastro.com/rcsi-2/ Ou visualizados no trecho de código abaixo. –CRIAÇÃO DO AMBIENTE PARA OS TESTES –CRIAÇÃO DA BASE USE master GO IF db_id(‘DEMO_RCSI’) IS NOT NULL DROP DATABASE DEMO_RCSI GO CREATE DATABASE DEMO_RCSI ON PRIMARY (NAME = ‘DEMO_RCSI_Data’,FILENAME = ‘C:TEMPDE MO_RCSI.mdf’,SIZE = 128 MB) LOG ON (NAME = ‘DEMO_RCSI_Log’, FILENAME = ‘C:TEMPDE MO_RCSI.ldf’,SIZE = 128 MB) GO USE DEMO_RCSI GO –CRIA A TABELA PESSOA IF object_id(‘TB_PESSOA’) IS NOT NULL M V T e c h | 28 SQL Server: Além do Conceito Blog Post Collection DROP TABLE TB_PESSOA GO CREATE TABLE TB_PESSOA ( ID_PESSOA INT IDENTITY CONSTRAINT PK_TB_PESSO A_ID_PESSOA PRIMARY KEY ,DATA_CONTRATACAO DATE DEFAULT GETDATE() ,NOME_PESSOA VARCHAR(60) ,BOL_EMPREGADO CHAR(1) ) GO –CRIA A TABELA EMPRESTIMO IF object_id(‘TB_EMPRESTIMO’) IS NOT NULL DROP TABLE TB_EMPRESTIMO GO CREATE TABLE TB_EMPRESTIMO ( ID_EMPRESTIMO INT IDENTITY CONSTRAINT PK_TB_E MPRESTIMO_ID_EMPRESTIMO PRIMARY KEY ,ID_PESSOA INT –CONSTRAINT FK_TB_PESSOA_TB_EMPRESTIMO FOREIGN KEY REFERENCES TB_PESSOA (ID_PESSOA) ,VALOR_EMPRESTIMO DECIMAL(10,2) ,LIBERACAO_EMPRESTIMO CHAR(1) ) –EXISTE O NÍVEL DE ISOLAMENTO –EXIBE INFORMAÇÃO SOBRE O NIVEL DE ISOLAMENTO ATUAL SELECT NAME ,CASE is_read_committed_snapshot_on WHEN 1 THEN ‘ENABLED’ WHEN 0 THEN ‘DISABLED’ END AS ‘Read_Committed_Snapshot’ FROM SYS.DATABASES WHERE NAME = ‘DEMO_RCSI’ –CARREGA DADOS NA TABELA PESSOA INSERT INTO TB_PESSOA (NOME_PESSOA, BOL_EMPRE GADO) VALUES (‘JOAO CASTRO’,‘S’) ,(‘MANOEL MAIA’,‘S’) ,(‘BENEDITO LIMA’,‘N’) ,(‘MARIA CASTRO’,‘N’) ,(‘CLEONTINA OLIVEIRA’,‘S’) M V T e c h | 29 SQL Server: Além do Conceito Blog Post Collection ,(‘CANDIDO DUARTE’,‘S’) –ALTERA O NÍVEL DE ISOLAMENTO PARA RCSI USE master ALTER DATABASE DEMO_RCSI SET READ_COMMITTED_S NAPSHOT ON –EXIBE DADOS DA TABELA PESSOA SELECT * FROM TB_PESSOA – ID_PESSOA DATA_CONTRATACAO NOME_PESSOA BOL_EMPREGADO –1 2013-07-27 JOAO CASTRO S –2 2013-07-27 MANOEL MAIA S –3 2013-07-27 BENEDITO LIMA N –4 2013-07-27 MARIA CASTRO N –5 2013-07-27 CLEONTINA OLIVEIRA S –6 2013-07-27 CANDIDO DUARTE S –ALTERA NÍVEL DE ISOLAMENTO –ALTER DATABASE DEMO_RCSI SET READ_COMMITTED_SNAPSHOT ON –ALTER DATABASE DEMO_RCSI SET READ_COMMITTED_SNAPSHOT OFF /*——————————————————————————*/ TRANSAÇÃO T1 –TRANSAÇÃO DE DEMISSÃO (T1) –EXIBE INFORMAÇÃO SOBRE O NIVEL DE ISOLAMENTO ATUAL SELECT NAME ,CASE is_read_committed_snapshot_on WHEN 1 THEN ‘ENABLED’ WHEN 0 THEN ‘DISABLED’ END AS ‘Read_Committed_Snapshot’ FROM SYS.DATABASES WHERE NAME = ‘DEMO_RCSI’ – PARA ALTERAR PARA O RCSI –USE MASTER –ALTER DATABASE DEMO_RCSI SET M V T e c h | 30 SQL Server: Além do Conceito Blog Post Collection READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE –INICIO DA TRANSAÇÃO DE UPDATE BEGIN TRAN T1 SELECT * FROM TB_PESSOA WHERE NOME_PESSOA = ‘JOAO CASTRO’ USE DEMO_RCSI GO UPDATE P SET P.BOL_EMPREGADO = ‘N’ FROM TB_PESSOA P WHERE NOME_PESSOA = ‘JOAO CASTRO’ GO SELECT * FROM TB_PESSOA WHERE NOME_PESSOA = ‘JOAO CASTRO’ –ROLLBACK TRAN T1 –COMMIT TRAN T1 –ABRA A SEGUNDA TRANSAÇÃO EM UMA NOVA JANELA (NEW QUERY)E FAÇA A OPERAÇÃO DE EMPRESTIMO (T2) /*——————————————————————————*/ TRANSAÇÃO T2 –TRANSAÇÃO DE EMPRÉSTIMO (T2) —- GARANTIR QUE ESTEJA COM RCSI HABILITADO –USE MASTER –ALTER DATABASE DEMO_RCSI SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE –GO —————————————————————————————— –INICIO DA TRANSAÇÃO DE UPDATE BEGIN TRAN T2 USE DEMO_RCSI GO INSERT INTO TB_EMPRESTIMO SELECT ID_PESSOA, ‘20000’,‘S’ FROM TB_PESSOA P WHERE NOME_PESSOA = ‘JOAO CASTRO’ COMMIT TRAN T2 —————————————————————————————— SELECT * FROM TB_EMPRESTIMO SELECT * FROM TB_PESSOA —————————————————————————————— M V T e c h | 31 SQL Server: Além do Conceito Blog Post Collection –VEJA O RESULTADO ANTES DO COMMIT DA T1 (TRANSAÇÃO DE DEMISSÃO) SELECT P.ID_PESSOA, P.NOME_PESSOA, E.VALOR_EM PRESTIMO, P.BOL_EMPREGADO,E.LIBERACAO_EMPREST IMO FROM TB_EMPRESTIMO E JOIN TB_PESSOA P ON E.ID_PESSOA = P.ID_PESSOA —————————————————————————————— –EXECUTE O COMMIT DA TRANSAÇÃO T1 E RODE NOVAMENTE O RESULTADO. OBSERVER QUE HÁ ERRO DE NEGÓCIO –POIS FOI LIBERADO EMPRÉSTIMOI PARA UMA PESSOA QUE NÃO ESTÁ EMPREGADA. SELECT P.ID_PESSOA, P.NOME_PESSOA, E.VALOR_EM PRESTIMO, P.BOL_EMPREGADO,E.LIBERACAO_EMPREST IMO FROM TB_EMPRESTIMO E JOIN TB_PESSOA P ON E.ID_PESSOA = P.ID_PESSOA RESUMINDO: P RÓS E C ONTRAS DO RCSI: Reduz consideravelmente problemas provenientes de bloqueios. Habilitação fácil e rápida. Contras do Read Committed Snapshot Isolation: M V T e c h | 32 SQL Server: Além do Conceito Blog Post Collection Não é útil em bloqueios entre transações de update. Bloqueios com verificação de constraints também não são beneficiados. Pode resultar com algum erro negocial não esperado, caso não seja bem mapeado. CONCLUSÃO: O RCSI é passível de utilização em qualquer ambiente, desde que os “poréns” sejam bem mapeados e os erros provenientes sejam mitigados, com o uso de HINTS (Ex: (SELECT * FROM TABELA WITH (READCOMMITTED)), Alterando o nível de isolamento nas transações que necessitam que os bloqueios aconteçam entre outros meios que podem ser utilizados. READ COMMITTED SNAPSHOT ISOLATION – APRECIE COM MODERAÇÃO REFERÊNCIAS http://msdn.microsoft.com/pt-br/library/ms173763.aspx http://msdn.microsoft.com/en-us/library/tcbchxcb(v=VS.80).aspx Grande abraço, Edvaldo Castro http://edvaldocastro.com M V T e c h | 33 SQL Server: Além do Conceito Blog Post Collection Artigos técnicos: O guia definitivo (ou não) Estar presente e participar ativamente de uma comunidade, sempre ajuda no crescimento das pessoas, seja ele profissional, pessoal, religioso ou quaisquer outros âmbitos. Para quem trabalha na área de TI particularmente, esta participação pode culminar em uma curva de aprendizado e crescimento profissional muito mais acentuada do que se o profissional se isolar e caminhar sozinho na carreira. Basicamente é possível participar de comunidades consumindo informações compartilhadas e compartilhando informações e conhecimentos. Algumas das principais formas de compartilhar conhecimento e informações são: Palestras (presenciais e online), Redes Socais em geral, vídeos, Wiki e Blogs com postagens técnicas. Para aqueles que se aventuraram, ou desejam se aventurar com a redação e compartilhamento de textos técnicos, a seguir existe uma serie de pontos importantes que devem ser observados na intenção de que erros sejam evitados e uma melhor qualidade seja alcançada. M OTIVAÇÃO Existem diversos motivos que podem e levam profissionais à iniciarem uma efetiva participação em comunidades técnicas e criarem seus próprios blogs pessoais, ou mesmo escreverem para canais já bem conhecidos. Com motivações diferentes, geralmente os objetivos são comuns: exposição profissional, compartilhamento de conhecimento, networking e reconhecimento. Abaixo, alguns pontos que são relevantes e que podem influenciar direta ou indiretamente os resultados desta decisão de tornar-se público através principalmente de artigos técnicos. R ISCOS E O PORTUNIDADES A “Exposição Profissional” proveniente da decisão de escrever artigos técnicos é ambígua, ou seja, pode ser uma excelente oportunidade de se M V T e c h | 34 SQL Server: Além do Conceito Blog Post Collection criar um ótimo círculo de contatos profissionais, networking de alto nível e gerar grandes benefícios nos âmbitos profissional e pessoal, porém esta mesma “Exposição Profissional” pode ser extremamente perigosa e prejudicial à carreira do profissional, caso este não tome alguns cuidados básicos na hora de expor-se através de seus textos, por exemplo: Textos não fidedignos, com erros de português, dentre outros graves erros que estão melhor detalhados adiante, neste artigo. Q UANDO C OMEÇAR ? Tendo-se conhecimentos dos riscos e oportunidades, e considerando-se apto a dar início ao trabalho de compartilhamento de informações via textos técnicos (ou não), existem alguns importantes pré-requisitos a serem seguidos, para aumentar a probabilidade de que o texto a ser publicado seja bem recebido e faça “sucesso”. P ESQUISE Há um grande equívoco por parte de muitos autores de blogs, que é o conhecimento relacionado a um determinado assunto. Muitas pessoas, quando propõe-se a escrever um artigo técnico, enganam-se e pensam já saber o suficiente para não ser necessário fazer nenhuma pesquisa adicional. Mero engano, todo e qualquer conteúdo técnico, fica muito melhor apresentado, se expor pontos de vistas diferentes, ou mesmo conteúdo de fontes variadas, para defender um ponto de vista, ou mesmo descrever algo. L EIA E ESTUDE MUITO Leitura e estudo, nunca é demais. E quanto mais conhecimento sobre o assunto a ser dissertado, melhor e mais rico ficará o artigo técnico. É sempre muito importante estudar, ler e fazer tantos testes quantos possíveis antes de publicar o artigo, visto que uma vez publicado, seu texto estará exposto para o mundo inteiro a qualquer momento para visualização de qualquer pessoa que quiser visualizá-lo, e conforme já citado anteriormente, pode ser muito bom ou muito ruim esta exposição. M V T e c h | 35 SQL Server: Além do Conceito Blog Post Collection F AÇA CITAÇÕES E REFER ÊNCIAS Um ponto não menos importante que os anteriores é a existência de citações e referências no artigo técnico dos textos que foram escritos por outros autores. É frustrante para um autor, ver que todo trabalho de pesquisa e estudo que ele teve para escrever determinado trecho de artigo, ou mesmo um artigo completo, e repentinamente ver este “roubado” e publicado sem referência em outro local, que até então era desconhecido. É até mesmo uma questão de respeito e demonstração de maturidade e bom senso, que ficarão explícitos aos leitores do artigo em questão. R EVISÃO P ERIÓDICA (N ÃO OBRIGATÓRIA ) Esta não é uma necessidade extremamente importante, mas esporadicamente é interessante ler alguns de seus posts / artigos técnicos para que se por algum acaso houver algum erro (digitação, português ou conceitual), este possa ser corrigido. Revise sua estratégia / metodologia Um Blog baseado no dia a dia, ou na carreira de um profissional, deve acompanhar as mudanças que naturalmente ocorrem na carreira. Um bom exemplo é a tendência de migração de vários serviços de tecnologia para a nuvem. Se você fala sobre infraestrutura de servidores (Windows ou Linux), por exemplo, considere começar a estudar sobre computação na nuvem, e à medida que sentir-se confortável, os artigos naturalmente devem acompanhar esta mudança, isto fará com que os leitores, acompanhem as mudanças e talvez até se consiga mais leitores assíduos dos artigos técnicos publicados. M V T e c h | 36 SQL Server: Além do Conceito Blog Post Collection O ARTIGO TÉCNICO Abaixo, listo algumas características e especificidades referentes aos tipos mais comuns de artigos técnicos, detalhes do mesmo e alguns pontos de observação no que se refere à gramática na redação destes. TIPOS DE ARTIGOS TÉCNICOS D OCUMENTAÇÃO Este tipo de artigo técnico visa dissertar sobre algum produto, feature ou atividade, demonstrando sua finalidade sem se preocupar na apresentação dos métodos ou passo a passo para implementação. Este tipo de artigo técnico, geralmente é escrito quando são lançadas versões novas ou um produto totalmente novo, com a finalidade principal de demonstrar tal produto ou feature. H OW T O ( S ) Artigos técnicos deste tipo, são como tutoriais onde normalmente é descrito um passo a passo com detalhes de implementação, ativação ou quaisquer alterações que objetivem o autor do artigo a criá-lo. B ENCHMARKS E E XPERIÊNCIAS Este é um outro tipo de artigo bastante interessante, onde o autor do artigo, por necessidade ou ocasionalidade, passou por algum problema ou fez alguns testes que posteriormente demonstra em seu artigo técnico. Geralmente estes artigos são bem interessantes e demonstram situações do dia a dia e podem agregar bastante conhecimento à quem atua ou possui ambiente similar ao descrito no artigo. M V T e c h | 37 SQL Server: Além do Conceito Blog Post Collection O ARTIGO TÉCNICO EM SI E STRUTURA Um artigo técnico (ou não) bem estruturado é muito importante, pois facilita e contribui para que a leitura fique mais agradável e entendível. Se a ideia é escrever muito, este tópico é especialmente importante, pois quanto maior o texto, mais cansativa e desestimulante fica a leitura, caso a mesma não esteja bem estruturada, sendo o inverso igualmente verdadeiro, quando mais bem estruturado, melhor e mais agradável se torna a leitura do mesmo. Por um texto bem estruturado, entende-se a divisão do mesmo (introdução, desenvolvimento e conclusão), estruturação utilizando-se marcadores, definições de fontes tradicionais de tamanhos proporcionais e principalmente a divisão em tópicos e subtítulos, determinando exatamente o assunto que determinado ponto do artigo trata. L INGUAGEM Não se pode dizer que é correto ou incorreto escrever de uma forma completamente informal ou de forma muito formal. O ideal é definir o público alvo que se deseja atingir, e escrever da forma correta para este público alvo. Por exemplo, talvez escrever de forma extremamente formal, um artigo onde os principais leitores serão jovens universitários em início de carreira, pode tornar a leitura um tanto quanto chata e cansativa. Da mesma forma, não é aconselhado um texto muito informal, quando o público alvo são diretores e presidentes de empresas de Tecnologia, ou outras. Sendo seu artigo formal ou não, o importante é o correto direcionamento do artigo ao seu respectivo público alvo. P ÚBLICO A LVO Conforme mencionado anteriormente, além de escrever da maneira correta para o público alvo correto, é preciso conhecer e saber para quem se está M V T e c h | 38 SQL Server: Além do Conceito Blog Post Collection escrevendo, com isto é possível adequar a linguagem, estrutura e conteúdo do seu artigo. GRAMÁTICA E VITE OS ERROS MAIS COMUNS ( DIGITAÇÃO , GÍRIAS , CONCORDÂNCIA , ETC ) Um dos pontos mais importantes em um artigo técnico é a clareza e assertividade com que se escreve um texto, relacionado à gramática do idioma no qual este texto é escrito. Se o texto está em português por exemplo, é imprescindível tomar todos os cuidados com erros de concordância, gírias, neologismos e até mesmo com erros de digitação, que naturalmente podem aparecer durante a redação do mesmo. Um texto bem escrito e gramaticalmente correto corrobora muito para que ao final da leitura, o leitor tenha prestado atenção ao conteúdo e tenha tido bom entendimento do que pretendia-se ter passado, do que ficar em mente os “assassinatos” ao idioma encontrados durante a leitura. S OLICITE R EVISÕES (A MIGOS , C OMUNIDADE , P ARENTES , S R . J OAQUIM ) Uma ferramenta gratuita e muito útil é a revisão antes da publicação. É bem provável que uma pessoa que possui um local onde publicar seus artigos (técnicos ou não), conheça outras pessoas do meio, que podem ler e avaliar o texto antes de o mesmo ser publicado. Ainda assim, caso não seja possível encontrar alguém que possa revisar o texto, é possível solicitar que uma ou mais pessoas o façam (mesmo não sendo do meio relacionado ao conteúdo do artigo). Se possível, é aconselhável que sejam feitas revisões técnicas e gramaticais, assim mitiga-se o risco de incorreções tanto na parte técnica proposta no artigo, como também a parte gramatical que é tão importante quanto. Abaixo, listo alguns pontos importantes com relação à algumas principais preocupações e com a publicidade quando se está desenvolvendo um artigo técnico. M V T e c h | 39 SQL Server: Além do Conceito Blog Post Collection PRINCIPAIS PREOCUPAÇÕES S EMPRE Solicite que alguém revise seus textos antes de publicá-los Cite as fontes das informações Pesquise em fontes fidedignas Não assassine o idioma Deixe claro que o texto é sua opinião, não uma verdade absoluta N UNCA Escreva com pressa de publicar Publique um artigo sem pelo menos uma revisão Copie ou reblogue algo, sem autorização do autor do texto original Diga que sua forma é a única maneira existente P UBLICIDADE Canais disponíveis Blog Pessoal Technet Wiki Facebook (Pages and Profile) Twitter M V T e c h | 40 SQL Server: Além do Conceito Blog Post Collection FAÇA BARULHO Divulgue sempre seus artigos técnicos. Cuidado para não se tornar um spammer ou um chato bloqueado CONCLUSÃO Em resumo, um blog ou canal de textos técnicos quando bem escrito pode alavancar uma carreira, tornar seu autor conhecido por seus ótimos artigos e consequentemente rendendo bons resultados (convites, empregos, propostas, networking, etc). Em contrapartida, se o texto não é bem escrito e não toma-se diversos cuidados (alguns mencionados no texto supracitado) esta exposição pode ter o efeito contrário e fazer as oportunidades, a “fama” e propostas sumirem, visto que você pode estar mostrando a todos em seu texto seus pontos fracos (gramática, conhecimento técnico, etc). Eu gostaria ainda de esclarecer que tudo o que foi escrito foi baseado em minhas preocupações e minha opinião. De forma alguma é a representação absoluta da verdade. Se você concorda, discorda ou tem algo a acrescer, será muito bem vindo nos comentários…. Obrigado por chegar até aqui, Grande abraço, Edvaldo Castro http://edvaldocastro.com M V T e c h | 41 SQL Server: Além do Conceito Blog Post Collection Diego Nogare www.diegonogare.net Partition Table Particionamento de Tabelas Fala galera, esses dias atrás estava fazendo uma apresentação sobre SQL Server 2012 e surgiu uma dúvida de um dos participantes sobre particionamento horizontal de tabelas. Decidi procurar alguns materiais em português e não achei muitos, então resolvi dar minha contribuição sobre esse assunto. Bom, os benefícios de se utilizar Partition Table no SQL Server são muitos, mas antes de falar dos benefícios, vamos criar um banco de dados de exemplo para simular uma tabela do mundo real e depois entender o que é o Partition Table. Esse script cria um banco que irá simular uma tabela de visitas de um museu, imaginando que o museu foi inaugurado no dia 1º de Janeiro de 2012 e hoje é dia 31 de Dezembro, totalizando neste 1 ano de atividades 1 milhão de visitas. Com os próximos sub-capítulos vamos criar as partições, separar esses dados e deixar cada agrupamento (visitas do mesmo mês) em uma tabela específica. Depois podemos comparar os prós e contras desta técnica. CREATE DATABASE dbMuseu GO USE dbMuseu GO CREATE TABLE tbVisitas (id INT IDENTITY(1,1) PRIMARY KEY ,nome VARCHAR(50) ,data DATE) GO M V T e c h | 42 SQL Server: Além do Conceito Blog Post Collection INSERT INTO tbVisitas (nome, data) VALUES (newid(), /*Dados aleatórios para o nome*/ convert(date, convert(varchar(15),'2012-' + convert(varchar(5),(convert(int,rand()*12))+1 ) + '-' + /* Gerar mês aleatório */ convert(varchar(5),(convert(int,rand()*27))+1 ) /* Gerar dia aleatório */ ))) GO 1000000 Ótimo, agora que já temos nossa base para simular… Vamos entender o que é o particionamento! O particionamento horizontal de tabelas é uma técnica que utilizamos na arquitetura da estrutura de dados, para melhorar a performance/desempenho/gerenciamento do sistema gerenciador de banco de dados. Esta técnica consiste em dividir os dados, baseado em um parametro, em tabelas e File Groups diferentes. Para exemplificar, veja na imagem abaixo os dados que estavam na tabela Visitas foram divididos em 12 tabelas, cada uma armazenando os dados de um mês específico. A tabela azul armazena visitas de Janeiro, a tabela verde armazena de Fevereiro e a tabela laranja armazena visitas de Dezembro. Porém, a tabela preta representa a consulta de todas as visitas do ano inteiro… M V T e c h | 43 SQL Server: Além do Conceito Blog Post Collection No decorrer dos próximos sub-capítulos, vamos trabalhar em atividades específicas necessárias para particionar com sucesso essa tabela de visitas do museu. C ENÁRIOS /B ENEFÍCIOS Fala galera, uma duvida frequente quando falamos em particionar uma tabela, é: Porque Particionar?! Pensamos em particionamento de tabelas quando ela possui muitos registros e precisamos melhorar escalabilidade, performance e gerenciamento. Normalmente desenhamos as tabelas para armazenar informações de uma entidade específica, como Funcionarios, Vendas ou Produtos. Não é porque desenhamos e entendemos este modelo de dados que otimizamos a tabela para receber grande volume… Já encontrei por ai, e não foi só uma vez, tabelas com quantidade de dados significativa e que não tinha nenhum tipo de índice. Acreditem, é triste mas é verdade! Quando falamos de bancos de dados realmente grandes, nos referimos à VLDB (Very Large Database). Não é regra que um VLDB possua tabelas que precisam ser particionadas. Para particionar uma tabela um dos pontos mais importante a se levar em consideração é o tempo gasto para dar manutenção nesta tabela, e não somente a quantidade de registros. Imaginem o caso de uma tabela de Produtos de um e-Commerce que fica 2h/dia lenta porque está reorganizando/reconstruindo o índice, ou fica travada quando estão rodando algum relatório… Esse tipo de tabela pode ser particionada para melhorar o tempo de resposta das consultas e garantir que o e-Commerce continue fazendo suas vendas online. Pensando em relatórios, isso pode causar uma lentidão grande no seu RDBMS (Relational Database Management System) quando tem um ROLAP (Relational On Line Analytical Processing) realizando agregações. Se uma tabela com 1 milhão de registros precisa agregar as vendas por mês, o processamento irá trabalhar com todas as linhas da tabela e fará o somatório. Imaginando este mesmo cenário em um ambiente particionado, cada partição faz suas agregações e no final do processamento, você terá uma resposta mais rápida e seu ambiente continuou respondendo com rapidez. Um outro tipo de particionamento de tabelas pode ser feito para separar dados “quentes” e M V T e c h | 44 SQL Server: Além do Conceito Blog Post Collection histórico. Os dados quentes são os dados que você trabalha atualmente, por exemplo, os dados do trimestre atual e os dados de histórico são os dados dos trimestres passados. Se você separar os dados da sua tabela a cada 3 meses, você pode deixar os dados atuais em discos mais nobres do seu storage (SSD) e os dados de histórico em outros discos menos nobres (SAS ou SATA). Imagine a necessidade de consultar as vendas do ultimo ano, com a tabela particionada, você faria isso sem ter nenhuma concorrencia com as transações que estão acontecendo atualmente na tabela. D EFINIÇÕES /T ERMINOLOGIAS Fala galera, para implementar o particionamento horizontal de tabelas, é importante conhecer as definições e terminologias utilizadas. Para alinharmos, vou falar do que é fundamental para você entender e aplicar essa tecnologia nos seus projetos. Para começar, vamos entender a estrutura de armazenamento do Partition Table. Esta forma de trabalhar se aplica desde SQL Server 2005 até o 2012, antes disso, com o SQL Server 7 ou 2000, até onde me lembro, tinha que fazer manualmente a quebra dos dados nas tabelas particionadas e a consulta era feita através de uma VIEW com UNION ALL de todas as tabelas particionadas… um verdadeiro parto! Desde o SQL Server 2005, quando criamos uma tabela e/ou índice no nosso banco e não definimos onde ele será armazenado, ele fica no filegroup default. Porém, podemos criar a tabela e/ou índice em um partition scheme. O partition scheme faz um mapeamento de um ou mais filegroups, mas para armazenar os dados nos arquivos físicos corretos (nos filegroups) ele usa o partition function, que por sua vez, contém o algoritmo que realmente identifica onde determinada linha será armazenada. A ordem cronológica é mais ou menos assim: M V T e c h | 45 SQL Server: Além do Conceito Blog Post Collection Ok, agora que entendemos de forma macro a estrutura de armazenamento, vamos entender conceitualmente como o SQL Server quebra os dados baseado em uma coluna da tabela. Para isso, é necessário definir o Range que o algoritmo de particionamento irá usar para separar os dados de forma correta e informar o partition function (que irá armazenar no local indicado). Esse Range atua juntamente ao Partition Key, que é uma coluna única existente na tabela e é utilizada como separador lógico dos dados. Depois dos dados separados em tabelas específicas, é possível trabalhar com os dados das tabelas não só fazendo consultas, mas também juntando (Merge) e/ou particionando ainda mais as tabelas (Split). Também usa-se o Switch para “converter” uma tabela que estava sendo usada como atual, com dados quentes, para ser entendida como histórico. M V T e c h | 46 SQL Server: Além do Conceito Blog Post Collection Pegando como base o database criado no sub-capitulo de Particionamento de Tabelas, se for separar os dados com base em cada mês, o Partition Key seria a coluna Data e o Range seria cada período que quero utilizar, baseado em um início e fim da coleção de dados. Seria algo assim: Intervalo 1 2 … 12 Inicio 01/01/2012 01/02/2012 … 01/12/2012 Fim 31/01/2012 28/02/2012 … 31/12/2012 Fiquem atentos à essas nomenclaturas, a medida que precisarmos usar cada uma delas vou explicar em detalhes suas caracteristicas e funcionamento. M V T e c h | 47 SQL Server: Além do Conceito Blog Post Collection C RIANDO F ILEGROUP Fala galera, mesmo o Filegroups sendo o “final” do processo de criar a Partition Table pois é onde os dados serão armazenados de fato, vamos criálos primeiro. Depois de criar os filegroups podemos voltar e criar o Partition Function e o Partition Scheme. Antes de criar o filegroup, vamos relembrar um pouco de conceito do SQL Server. Todos os dados de uma tabela são armazenados em um agrupador chamado Página que possui 8Kb de tamanho. Independente de uma página estar com apenas 1 registro, ou totalmente preenchida com dados, ela ocupa 8Kb de tamanho. Outra caracteristica é que dentro de uma página são armazenados somente dados de uma mesma tabela. Se neste exemplo abaixo existisse somente 1 funcionário e 1 produto, existiriam 2 páginas criadas. O conjunto de 8 páginas é chamado de Extent, que por sinal, tem 64Kb de tamanho (8Kb de cada uma das 8 páginas). Mais pra frente vamos entender o porque é importante saber o tamanho de uma Página e de um Extent. Os Databases são criados no filegroup Default, se não for especificado em qual filegroup deve ser criado. Por padrão, no SQL Server 2012, os filegroups M V T e c h | 48 SQL Server: Além do Conceito Blog Post Collection são armazenados dentro da pasta \Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA com o nome do Database que você criou. Se você quiser especificar o filegroup na hora de criar seu Database, deve adicionar o código T-SQL junto à criação do seu Database. Veja abaixo a criação do dbMuseu_2 informando o filegroup via código T-SQL. CREATE DATABASE dbMuseu_2 ON ( NAME = dbMuseu_2, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\dbMuseu_2.m df', SIZE = 10, MAXSIZE = 50, FILEGROWTH = 5 ) LOG ON ( NAME = dbMuseu_log, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\dbMuseu_2_l og.ldf', SIZE = 5MB, MAXSIZE = 25MB, FILEGROWTH = 5MB ) ; GO Esta criação do dbMuseu_2 é só para exemplificar como especificar o filegroup na hora da criação do Database, fique a vontade para excluir o dbMuseu_2, caso tenha criado. Quando se cria mais de um filegroup por Database, os novos arquivos de filegroup possuem a extensão .NDF ao invés de .MDF. Também temos o arquivo .LDF que são os arquivos de LOG das transações que o Database processa. Os Databases já criados, tanto o dbMuseu (criado no primeiro sub-capitulo) quanto o dbMuseu_2 criado agora, possuem apenas 1 Filegroup. Veja na imagem abaixo estes arquivos físicos. M V T e c h | 49 SQL Server: Além do Conceito Blog Post Collection Vamos criar agora outros filegroups para o dbMuseu (criado no primeiro subcapitulo) para poder separar os dados da tabela tbVisitas e utilizar o propósito destes capítulo, o Partition Table! Primeiro vamos adicionar o nome lógico dos Filegroups ao nosso Database. Como já temos o dbMuseu criado, vamos alterar o banco de dados ao invés de criar um novo. Veja o código T-SQL abaixo: USE MASTER GO ALTER DATABASE [FG2012_JAN] ALTER DATABASE [FG2012_FEV] ALTER DATABASE [FG2012_MAR] ALTER DATABASE [FG2012_ABR] ALTER DATABASE [FG2012_MAI] ALTER DATABASE [FG2012_JUN] ALTER DATABASE [FG2012_JUL] ALTER DATABASE [FG2012_AGO] ALTER DATABASE [FG2012_SET] ALTER DATABASE [FG2012_OUT] dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP dbMuseu ADD FILEGROUP M V T e c h | 50 SQL Server: Além do Conceito Blog Post Collection ALTER DATABASE dbMuseu ADD FILEGROUP [FG2012_NOV] ALTER DATABASE dbMuseu ADD FILEGROUP [FG2012_DEZ] GO Para confirmar os nomes lógicos adicionados ao seu Database, você pode ir até as propriedades do banco, clicando com o botão direito em dbMuseu >> Properties, e então nas opções da esquerda, vá até Filegroups como na imagem abaixo, ou então através do código T-SQL: USE dbMuseu GO sp_helpfilegroup GO M V T e c h | 51 SQL Server: Além do Conceito Blog Post Collection Pronto, os nomes lógicos estão criados, agora é o momento de criar os arquivos físicos e associá-los à esses nomes lógicos dos filegroups. Para isso, é necessário realizar outro código DDL de Alter Database, veja esse código abaixo: USE MASTER GO ALTER DATABASE dbMuseu ADD FILE (NAME = 'FG2012_01_JAN' ,FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\FG2012_01_J AN.ndf') TO FILEGROUP [FG2012_01_JAN] GO M V T e c h | 52 SQL Server: Além do Conceito Blog Post Collection Neste código acima, criamos fisicamente o filegroup FG2012_01_JAN.NDF baseado no nome lógico criado anteriormente, e que receberá somente os dados de Janeiro/2012 quando particionarmos os dados. Voltando para a pasta \Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA, podemos ver o arquivo físico já criado: Devemos replicar esse ultimo código de Alter Table para todos os outros Filegroups que precisamos criar, isso é: Fevereiro, Março, Abril … até Dezembro. Sempre lembrando de alterar a localização do arquivo, o nome e o nome do filegroup. Para verificar que todos arquivos foram criados, outra alternativa é executar o código T-SQL abaixo: USE dbMuseu GO sp_helpfile GO M V T e c h | 53 SQL Server: Além do Conceito Blog Post Collection Nos próximos sub-capítulos, vamos criar o Partition Function e o Partition Scheme. C RIANDO P ARTITION F UNCTION Fala galera, logo depois de criar os filegroups e distribuir entre os discos existentes, é hora de criar o Partition Function que sustentará os algoritmos que farão a quebra dos dados. Quando se cria o partition function, é necessário definir os limites condicionais dos períodos. O primeiro ponto que precisa ter atenção é exatamente essa criação dos limites (boundary) informando se o período (range) terá como base de criação os dados do esquerdo (left) ou do lado direito (right), IMPORTANTE ressaltar que o boundary utilizado força que o valor informado será utilizado naquele range do contexto. Para exemplificar, vamos criar uma partição que teria os dados anteriores a 30/junho/2012 em uma partição e a partir de 01/julho2012 em outra. Para usar o boundary left, a quebra deve usar os dados à esquerda da condição, incluindo-a. Uma outra forma de dizer, é que os dados ficariam em <= 2012-06-30 Veja o código abaixo como ficaria essa partition function com left. CREATE PARTITION FUNCTION QuebraPelaEsquerda(date) AS RANGE LEFT FOR VALUES ('20120630') M V T e c h | 54 SQL Server: Além do Conceito Blog Post Collection Para usar o boundary right a quebra será a direita da condição, com a condição informada entrando na quebra, outra leitura para isso seria >= 2012-07-01 Veja o código abaixo como ficaria essa partition function com right. CREATE PARTITION FUNCTION QuebraPelaDireita(date) AS RANGE RIGHT FOR VALUES ('20120701') Voltando ao cenário do museu, que estamos utilizando durante todo este capítulo, vamos criar os partition functions baseados nos 12 meses de 2012. Vou escrever o código para boundary right, mas fique a vontade para escrever com o left, para estudar. Lembrando que para usar o left, ao invés de informar o primeiro dia de cada mês, você deve informar o ultimo dia do mês anterior. USE dbMuseu GO CREATE PARTITION FUNCTION MuseuPorMes(date) AS RANGE RIGHT FOR VALUES ('20120101', '20120201', '20120301', '20120401', '20120501', '20120601', '20120701', '20120801', '20120901', '20121001', '20121101', '20121201') Criamos 12 partition functions informando qual é a data inicial de cada uma delas dentro do dbMuseu, isso significa que os dados anteriores a 01/Janeiro/2012 estão armazenados em 1 partição unica, contendo os dados desde quando começaram a ser inseridos até o dia 31/12/2011. Outro ponto importante a ser lembrado é que os dados acima de 01/12/2012 estão todos M V T e c h | 55 SQL Server: Além do Conceito Blog Post Collection em uma mesma partição, visto que não existe uma próxima partição que encerra o range deste grupo iniciado em 1º de Dezembro. No próximo sub-capítulo, finalmente será criado o partition scheme… C RIANDO O P ARTITION S CHEME Fala galera, seguindo a sequência lógica do particionamento, uma vez os Partition Function criados, você deve associá-los aos Partition Scheme. O Partition Scheme é responsável por encaminhar os dados para os Filegroups corretos, por isso é muito importante nomear corretamente os Filegroups e os Partition Schemes. Quando fizemos a quebra dos dados no Partition Function MuseuPorMes, definimos 12 partições (uma para cada mês). Agora serão criados os “13 Partition Scheme” para os meses. Você deve estar se perguntando porque 13 e não 12. A ultima Partition Scheme irá receber os dados acima de 01/12/2012, e irá encaminhar para o Primary Filegroup. Veja o código: CREATE PARTITION SCHEME MuseuPorMesScheme AS PARTITION MuseuPorMes TO ( [FG2012_01_JAN],[FG2012_02_FEV],[FG2012_03_MA R] ,[FG2012_04_ABR],[FG2012_05_MAI],[FG2012_06_J UN] ,[FG2012_07_JUL],[FG2012_08_AGO],[FG2012_09_S ET] ,[FG2012_10_OUT],[FG2012_11_NOV],[FG2012_12_D EZ] ,[PRIMARY] ) GO Lembrando que o MuseuPorMes é o nome do Partition Function criado anteriormente. M V T e c h | 56 SQL Server: Além do Conceito Blog Post Collection Caso todas as partições estivessem apontando para o mesmo Filegroup, você poderia escrever uma sintaxe mais simples, apontando todas as partições para o Primary Filegroup. Veja como seria esse código: CREATE PARTITION SCHEME MuseuPorMesScheme AS PARTITION MuseuPorMes ALL TO ([PRIMARY]) GO Por final, você precisa criar a tabela informando qual será o Partition Scheme que irá controlar o armazenamento dos dados. No próximo subcapítulo vamos ver essa criação! C RIANDO A TABELA Fala galera, este é o ultimo sub-capítulo sobre a parte estrutural do Partition Table, e é onde se cria a tabela utilizando os conceitos vistos nos subcapítulos anteriores. Para conseguirmos comparar o desempenho de uma tabela com os dados em um unico Filegroup (tbVisitas) e a tabela com todo o Partition Table, criaremos uma segunda tabela (tbVisitas_2) exatamente com a mesma estrutura da tabela anterior e vamos popular com os mesmos dados inseridos anteriormente na tabela inicial. Veja a criação da tabela, informando o Partition Scheme (veja a linha 5) em frente ao ON, que pode ser colocado ou não na criação da tabela. Caso não informe, o SQL Server cria a tabela com o filegroup padrão, que geralmente é o primary. Quando informamos um Partition Scheme na criação da tabela, os dados passam a utilizar o Partition Scheme para escrever no filegroup correto, que na sequência consulta o Partition Function para saber qual é o algoritmo de quebra dos dados… M V T e c h | 57 SQL Server: Além do Conceito Blog Post Collection CREATE TABLE tbVisitas_V2 (id INT IDENTITY(1,1) ,nome VARCHAR(50) ,data DATE) ON MuseuPorMesScheme(data) GO E aqui é a inserção dos dados exatamente igual à tabela original: INSERT INTO TBVISITAS_V2(NOME,DATA) SELECT NOME,DATA FROM TBVISITAS GO Pra fixar a idéia, lembre-se da imagem postada no sub-capítulo de definições/terminologias: Com isso, conseguimos separar em diversos Filegroups, que por sua vez estão em discos separados, garantindo alta-performance nas consultas realizadas nesta tabela. Façam testes com esta técnica aprendida nestes sub-capítulos em seus projetos e comprovem o desempenho! C OMPARATIVO DE INSERÇÃO DE DADOS EM UMA T ABELA COM C OLUMN S TORE I NDEX NO SQL S ERVER 2012 Fala galera, o ColumnStore Index é um novo formato de índice que foi lançado junto ao SQL Server 2012, este índice usa um padrão de compressão M V T e c h | 58 SQL Server: Além do Conceito Blog Post Collection de dados proprietário da Microsoft e altera o formato de armazenamento dos dados nas páginas do índice. A primeira vez que um registro é inserido no índice, ele registra o dado bruto, qualquer outra aparição deste mesmo dado dentro do índice, o SQL faz um apontamento de memória para o primeiro registro, diminuindo significativamente o tamanho da página com os índices. Este novo formato de índice não chegou para substituir os já convencionais e úteis Clustered e Non-Clustered index, ele vem para atender um outro cenário. O armazenamento do ColumnStore Index altera a escrita dos dados do índice que estamos acostumados a ver em um padrão linear (como a figura abaixo). Para um formato colunar – por isso o nome ColumnStore – armazenando todos os registros da coluna em uma mesma página. Uma representação visual seria como da imagem abaixo: M V T e c h | 59 SQL Server: Além do Conceito Blog Post Collection Os ganhos de performance com o uso correto do ColumnStore Index varia entre 10 e 100X. Podendo, em alguns casos reais que já presenciei, chegar a retornos 400X mais rápidos. Porém o ColumnStore Index não é só maravilhas. A utilização deste índice em uma tabela a transforma em Read Only, impedindo manutenção nos dados já existentes. Este cenário de dados como somente leitura nos remete à ambientes de Data Warehouse, onde a informação armazenada sofre manutenção incremental em determinados momentos do ciclo e normalmente não é atualizada ou excluída. Em alguns casos sendo incrementado somente uma vez por noite, em outros cenários somente uma atualização semanal, em um terceiro podendo ser uma vez por mês. Isso varia de acordo com a necessidade da área de negócios. Agora, se a tabela está em um formato Read Only, como podemos inserir dados incrementais nela??? Pensando sobre como implementar estes incrementos, vem à mente 3 possibilidades. Podemos: 1) desabilitar, inserir e reabilitar o índice; 2) remover, inserir e recriar o índice; ou 3) então trabalhar com Particionamento de Tabelas, onde temos as partições com o índice e uma tabela onde serão inseridos os dados atuais. Para colocar em comparação estes três cenários, montei um ambiente de teste com aproximadamente 35Milhões de linhas e fiz comparativo entre eles. Veja o comparativo abaixo entre Logical Read dos três cenários, e também o tempo necessário para realizar cada atividade. M V T e c h | 60 SQL Server: Além do Conceito Blog Post Collection O teste consistiu em criar uma tabela com 33milhões de registros e aplicar o ColumnStore Index nesta tabela. Em seguida, adicionar mais 1.6Milhões de linhas… Realizamos o teste no mesmo ambiente 2 vezes, e tiramos a média M V T e c h | 61 SQL Server: Além do Conceito Blog Post Collection tanto de Logical Reads quanto de Elapsed Time do processo. Os resultados provam que a melhor solução, disparada, é a utilização de Partition Table. Caso alguém queira simular o processo que utilizei, segue abaixo a criação do ambiente e a população das tabelas com menos dados. É claro que para você simular a mesma coisa que fiz aqui, você precisa adaptar este código abaixo para seu cenário. /*******************************************/ /*********** CRIAÇÃO DO AMBIENTE ***********/ /*******************************************/ CREATE DATABASE ngrSolutionsDW GO USE ngrSolutionsDW GO /*******************************************/ /*********** LIMPEZA DO AMBIENTE ***********/ /*******************************************/ USE ngrSolutionsDW GO DROP SEQUENCE seq_Codigo GO DROP TABLE tabelaProducao GO DROP TABLE tabelaProducao_v2 GO DROP PARTITION SCHEME ps_DataAtualizacao GO DROP PARTITION FUNCTION pf_DataAtualizacao GO /*******************************************/ /********** POPULAÇÃO DO AMBIENTE **********/ /*******************************************/ CREATE TABLE tabelaProducao( id INT NOT NULL , idOrigem INT NOT NULL , nome VARCHAR(20) NOT NULL M V T e c h | 62 SQL Server: Além do Conceito Blog Post Collection , endereco VARCHAR(30) NOT NULL , dataCadastro date NOT NULL , dataAtualizacao date NOT NULL ON [PRIMARY] GO ) ALTER TABLE tabelaProducao WITH CHECK ADD CONSTRAINT [validarCodigo_V1_Check] CHECK (dataAtualizacao >= '2010-01-01' and dataAtualizacao < '2013-03-01') GO ALTER TABLE tabelaProducao CHECK CONSTRAINT [validarCodigo_V1_Check] GO CREATE SEQUENCE seq_Codigo AS INT INCREMENT BY 1 minvalue 1 maxvalue 10000 GO /* 1K registros de SETEMBRO 2012 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-5, convert(datetime, getdate())), dateadd(month,-5, convert(datetime, getdate()))) go 1000 /* 1K registros de OUTUBRO 2012 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) M V T e c h | 63 SQL Server: Além do Conceito Blog Post Collection values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-4, convert(datetime, getdate())), dateadd(month,-4, convert(datetime, getdate()))) go 1000 /* 1K registros de NOVEMBRO 2012 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-3, convert(datetime, getdate())), dateadd(month,-3, convert(datetime, getdate()))) go 1000 /* 1K registros de DEZEMBRO 2012 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-2, convert(datetime, getdate())), dateadd(month,-2, convert(datetime, getdate()))) go 1000 M V T e c h | 64 SQL Server: Além do Conceito Blog Post Collection /* 1K registros de JANEIRO 2013 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-1, convert(datetime, getdate())), dateadd(month,-1, convert(datetime, getdate()))) go 1000 /* 500 registros de FEVEREIRO 2013 */ insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), getdate(), getdate()) go 500 SET STATISTICS IO ON; SET STATISTICS TIME ON GO /*******************************************/ /*********** DISABLE / REBUILD *************/ /*******************************************/ /************ CRIAÇÃO DO INDEX *************/ /*******************************************/ CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO M V T e c h | 65 SQL Server: Além do Conceito Blog Post Collection /*******************************************/ /******** INSERIR NA TABELA DE PROD ********/ /*******************************************/ /* +1 em FEVEREIRO 2013 */ -- Forçar o erro por causa que a tabela está com ColumnStore Index insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), getdate(), getdate()) /*******************************************/ /************ DISABLE / REBUILD ************/ /*******************************************/ ALTER INDEX idx_csi_tabelaProducao ON tabelaProducao DISABLE GO ALTER INDEX idx_csi_tabelaProducao ON tabelaProducao REBUILD GO /*******************************************/ /************ POPULAR A TABELA *************/ /*******************************************/ ALTER INDEX idx_csi_tabelaProducao ON tabelaProducao DISABLE GO insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), M V T e c h | 66 SQL Server: Além do Conceito Blog Post Collection substring(convert(varchar(40),newid()),1,30), dateadd(month,-4, convert(datetime, getdate())), getdate()) go 1000 ALTER INDEX idx_csi_tabelaProducao ON tabelaProducao REBUILD GO /*******************************************/ /************** DROP / CREATE **************/ /*******************************************/ /************ CRIAÇÃO DO INDEX *************/ /*******************************************/ CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO /*******************************************/ /******** INSERIR NA TABELA DE PROD ********/ /*******************************************/ /* +1 em FEVEREIRO 2013 */ -- Forçar o erro por causa que a tabela está com ColumnStore Index insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), getdate(), getdate()) /*******************************************/ /************** DROP / CREATE **************/ /*******************************************/ DROP INDEX [idx_csi_tabelaProducao] ON tabelaProducao GO M V T e c h | 67 SQL Server: Além do Conceito Blog Post Collection CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO /*******************************************/ /************ POPULAR A TABELA *************/ /*******************************************/ DROP INDEX [idx_csi_tabelaProducao] ON tabelaProducao GO insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), dateadd(month,-4, convert(datetime, getdate())), getdate()) go 1000 CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO /*******************************************/ /************* PARTITION TABLE *************/ /*******************************************/ /********** CRIAÇÃO DAS PARTIÇÕES **********/ /*******************************************/ CREATE PARTITION FUNCTION [pf_DataAtualizacao](date) AS RANGE RIGHT FOR VALUES ('2012-09-01','2012-10-01','201211-01', '2012-12-01','2013-01-01','201302-01','2013-03-01') M V T e c h | 68 SQL Server: Além do Conceito Blog Post Collection GO CREATE PARTITION SCHEME [ps_DataAtualizacao] AS PARTITION [pf_DataAtualizacao] ALL TO ([PRIMARY]) GO /*******************************************/ /************ CRIAÇÃO DOS INDEX ************/ /*******************************************/ CREATE CLUSTERED INDEX [idx_DataCodigo] ON tabelaProducao(DataAtualizacao) ON ps_DataAtualizacao(dataAtualizacao) GO CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO /*******************************************/ /******** INSERIR NA TABELA DE PROD ********/ /*******************************************/ /* +1 em FEVEREIRO 2013 */ -- Forçar o erro por causa que a tabela está com ColumnStore Index insert into tabelaProducao(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), getdate(), getdate()) /*******************************************/ /******** CRIAÇÃO DA SEGUNDA TABELA ********/ /*******************************************/ CREATE TABLE tabelaProducao_V2 (id INT NOT NULL, idOrigem int NOT NULL, M V T e c h | 69 SQL Server: Além do Conceito Blog Post Collection nome VARCHAR(20) NOT NULL, endereco VARCHAR(30) NOT NULL, dataCadastro date NOT NULL, dataAtualizacao date NOT NULL) GO ALTER TABLE tabelaProducao_V2 WITH CHECK ADD CONSTRAINT[validarCodigo_V2_Check] CHECK (dataAtualizacao >= '2013-02-01' and dataAtualizacao < '2013-03-01') GO /*******************************************/ /************ CRIAÇÃO DOS INDEX ************/ /*******************************************/ CREATE CLUSTERED INDEX [idx_DataCodigo] ON tabelaProducao_v2(DataAtualizacao) ON [PRIMARY] GO /*******************************************/ /********* MOVIMENTAÇÃO DOS DADOS **********/ /*******************************************/ -- Conta os registros SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao GO SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao_v2 GO -- Movimenta os dados ALTER TABLE tabelaProducao SWITCH PARTITION 7 TO tabelaProducao_v2 GO -- Conta os registros SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], M V T e c h | 70 SQL Server: Além do Conceito Blog Post Collection max(dataAtualizacao) [MAIOR] FROM tabelaProducao GO SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao_v2 GO /* Fevereiro na TABELA 2 */ insert into tabelaProducao_V2(id, idOrigem, nome, endereco, dataCadastro, dataAtualizacao) values (next value for seq_Codigo, convert(int,rand()*100)+1, substring(convert(varchar(40),newid()),1,20), substring(convert(varchar(40),newid()),1,30), getdate(), getdate()) go 10 -- Conta os registros SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao GO SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao_v2 GO CREATE NONCLUSTERED COLUMNSTORE INDEX [idx_csi_tabelaProducao] ON tabelaProducao_v2 ( id, nome, endereco, dataCadastro, dataAtualizacao ) GO ALTER TABLE tabelaProducao_V2 switch to tabelaProducao partition 7 M V T e c h | 71 SQL Server: Além do Conceito Blog Post Collection GO -- Conta os registros SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao GO SELECT COUNT(0) [TOTAL], min(dataAtualizacao) [MENOR], max(dataAtualizacao) [MAIOR] FROM tabelaProducao_v2 GO Bom divertimento em seus testes! M V T e c h | 72 SQL Server: Além do Conceito Blog Post Collection Demetrio Silva demetriosilva.wordpress.com Tuning no SharePoint e SQL Server com o Developer Dashboard Tunin no SharePoint com Developer Dashboard INTRODUÇÃO Apesar do nome sugerir, esta ferramenta não é específica para desenvolvedores. Developer Dashboard é um recurso do SharePoint que ajuda os desenvolvedores a rastrear problemas de performance em componentes customizados ou não, dentro uma página. Seu uso é muito comum por desenvolvedores, pois possibilita que os mesmos repassem as informações das consultas SQL aos DBAs, para análise e possível tuning. A página do dashboard é carregada no endereço do site, acrescentando /_layouts/15/devdash.aspx ao final. Tempo que a página levou para carregar, quais componentes foram carregados, as consultas SQL executadas ( duração, plano de execução, etc), correlation id, logs ULS são exemplos de informações exibidas no dashboard. Por padrão, este recurso é desabilitado e este artigo vai mostrar como configurar e habilitar esta feature. Vale lembrar que o Developer Dashboard não pode ser usado na Central Admin. M V T e c h | 73 SQL Server: Além do Conceito Blog Post Collection C ONFIGURAÇÃO O Developer Dashboard requer que o Service Application “Usage & Health Data Collection” esteja configurado. Os passos abaixo mostram como verificar se o recurso está ou não configurado: 1 – No menu iniciar, abra a console “SharePoint 2013 Management Shell” conforme figura 1 M V T e c h | 74 SQL Server: Além do Conceito Blog Post Collection Figura 1 – Abrir console PowerShell 2 – Com a console aberta, execute o script abaixo conforme figura 2 Figura 2 – Script O script acima tenta criar o Service Application. Caso o mesmo já exista, mesmo com outro nome, ele gera um erro. O próximo passo é habilitar o Developer Dashboard. Copie e cole o script abaixo na mesma console do passo 2 e tecle enter: $service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService $dd = $service.DeveloperDashboardSettings $dd.DisplayLevel = "On" $dd.Update() Obs.: para desativar o Developer Dashboard basta executar novamente o script acima, trocando $dd.DisplayLevel = "On" por $dd.DisplayLevel = "Off". Por questões de performance, após realizar o throubleshooting, desabilite o Developer Dashboard. M V T e c h | 75 SQL Server: Além do Conceito Blog Post Collection Veja a execução do script na figura 3: Figura 3 – Habilitando o Developer Dashboard Visualizando o Developer Dashboard Neste momento, já temos o Developer Dashboard configurado. Os passos abaixo mostram como visualizar os dados na página, bem como, ilustra algumas de suas funcionalidades. 1 – Abra qualquer site da Farm. Neste exemplo, usamos o site http://palestras2013. No canto superior direito, clique no ícone “Iniciar painel de desenvolvimento” conforme figura 4 Figura 4 - Iniciar painel M V T e c h | 76 de desenvolvimento SQL Server: Além do Conceito Blog Post Collection 2 – Após o passo anterior, será aberto um pop-up igual ao da figura 5 Figura 5 – pop-up do painel Na guia “Solicitações”, podemos ver cada requisição às páginas no SharePoint. Basta clicar na solicitação desejada para que o painel mostre as informações sobre a mesma. No exemplo abaixo, clicamos na chamada à página “http://palestras2013/SitePages/Como Usar esta Biblioteca.aspx?AjaxDelta=1&isStartPlt1=1405695726064”, conforme figura 6 M V T e c h | 77 SQL Server: Além do Conceito Blog Post Collection Figura 6 – Página requisitada Na Figura 6, dentro da aba “Informações do Servidor” temos dois grids: a) “Estatísticas da Solicitação” – Com um resumo da solicitação. Exibe informações como Hora de Início, Duração Total para carregar a página, Servidor, Usuário, etc. b) “Estatísticas Agregadas” - Nela podemos ver o resumo das consultas SQL executadas, exibindo o número de consultas, duração total das consultas, etc. Seguindo para a aba “ULS”, podemos ver todas as entradas no log referentes à página que estamos analisando. Isso é fantástico, uma vez que o painel já faz o filtro no log e nos mostra tudo que está ocorrendo na página e foi registrado no log. Na figura 7, podemos ver o log ULS M V T e c h | 78 SQL Server: Além do Conceito Blog Post Collection Figura 7 – ULS Outra guia interessante é a SQL. Nela podemos ver o tempo de execução de cada consulta, o plano de execução, comando T-SQL, estatísticas de IO e algumas outras informações úteis. A figura 8 mostra a guia SQL: Figura 8 – SQL M V T e c h | 79 SQL Server: Além do Conceito Blog Post Collection Para visualizar mais informações sobre a consulta, basta clicar no nome da mesma. A figura 9 mostra as informações exibidas ao clicar na consulta “SELECT t1.[Tim”: Figura 9 – Informações da consulta Ao clicar em plano de execução, também podemos ver e/ou salvar o plano gerado para a consulta. Existem diversas outras abas no painel que mostram informações úteis. Para mais informações acesse o link: http://technet.microsoft.com/ptbr/library/jj219701(v=office.15).aspx. CONCLUSÃO Este artigo mostrou como configurar o Developer Dashboard, uma ferramenta essencial para os desenvolvedores em SharePoint. Também mostramos algumas de suas funcionalidades. M V T e c h | 80 SQL Server: Além do Conceito Blog Post Collection Esta é apenas uma das diversas maneiras que o SharePoint nos fornece para analisar o ambiente e ajustar a performance da Farm. M V T e c h | 81 SQL Server: Além do Conceito Blog Post Collection Acessando dados do SharePoint com PowerPivot INTRODUÇÃO É um cenário muito comum as empresas adotarem o SharePoint como ferramenta de colaboração e uma das verticais do SharePoint são os sites. Dentro dos sites, temos várias listas e bibliotecas, que armazenam reuniões, cadastros de clientes, tarefas dentre outros dados. Com os dados já armazenados, uma necessidade muito comum é gerar relatórios dos dados das listas. Existem várias formas de gerar relatórios de listas e uma delas é através do PowerPivot, que será o foco deste artigo. Este artigo usará uma funcionalidade do SharePoint que expõe os dados da lista em forma de Atom feed e como importar os dados Atom Feed para dentro do data model PowerPivot. R EQUISITOS É necessário instalar o runtime ADO.NET nos servidores WFE – Web FrontEnd da Farm. Mais informações aqui ou nos links abaixo: http://go.microsoft.com/fwlink/?LinkId=221066: Windows Server 2008 R2 http://go.microsoft.com/fwlink/?LinkId=195068: Windows Server 2008 C OMO FUNCIONA Usaremos os dados do banco de dados adventureworks2012, onde neste outro artigo, os dados da tabela person foram exportados para Excel e importados no SharePoint, criando assim uma lista no SharePoint com os dados da planilha do Excel. O acesso aos dados será realizado pela REST Interface, que permite acesso M V T e c h | 82 SQL Server: Além do Conceito Blog Post Collection às listas e bibliotecas do SharePoint no formato de relational data service. Neste caso, as operações de leitura, atualização, criação e exclusão de itens são feitas através da SharePoint Foundation REST, que provê várias operações para os Web Services RESTFull. Todas mapeadas diretamente para GET, POST, PUT e DELETE HTTP Verbs. A URL para acesso à REST tem o seguinte padrão http://NomeDoSiteSharePoint/_vti_bin/ListData.svc, onde, nos exemplos o site usado (NomeDoSiteSharePoint) se chama http://palestras2013/, logo, a URL dos exemplos terá o formato http://palestras2013/_vti_bin/ListData.svc. Ao acessar a REST Interface do site de exemplo a tela abaixo é exibida: (Figura 1 – REST Interface do site http://palestras2013/) Para acessar os dados de uma lista específica, basta adicionar o nome da lista no final da URL, deixando-a assim http://palestras2013/_vti_bin/ListData.svc/Categorias/Categorias. Onde Categorias é o nome da lista que foi importada da base M V T e c h | 83 SQL Server: Além do Conceito Blog Post Collection AdventureWorks2012 para o SharePoint. O conteúdo da lista pode ser visto na Figura 2 e o resultado do REST para esta lista pode ser visto na Figura 3. (Figura 2 – Lista M V T e c h | 84 de Categorias) SQL Server: Além do Conceito Blog Post Collection (Figura 3 – Lista de Categorias Atom Feed) I MPORTAR PARA O P OWER P IVOT NO E XCEL Para realizar a importação da lista no PowerPivot do Excel, basta abrir a janela do PowerPivot e na guia "From Data Service" clicar em From OData Data Feed conforme Figura 4. (Figura 4 – Selecionar fonte de dados) Na tela seguinte, em Data Feed Url, informe a Url da lista que deseja acessar via REST. Neste caso, http://palestras2013/_vti_bin/ListData.svc/Categorias. A figura 5 ilustra o exemplo: M V T e c h | 85 SQL Server: Além do Conceito Blog Post Collection (Figura 5 – Conexão do PowerPivot ao Feed) Clique em next, finish e a tela de importação será exibida conforme abaixo. (Figura 6 – Finalizando a importação) Por fim, a figura 7 mostra os dados da lista do SharePoint já importados para M V T e c h | 86 SQL Server: Além do Conceito Blog Post Collection dentro (Figura do 7 – PowerPivot. Dados importados) A partir deste ponto é possível usar os dados da lista dentro do PowerPivot e usufruir de todas as funcionalidades do mesmo. Exportar do SharePoint para o PowerPivot Caso a Farm e o Site Collection que você esteja usando já tenha o PowerPivot configurado, a importação da lista para o PowerPivot é ainda mais simples. Basta selecionar a opção "Exportar como Feed de Dados" na lista desejada conforme figura 8. M V T e c h | 87 SQL Server: Além do Conceito Blog Post Collection (Figura 8 – Exportando lista do SharePoint para o PowerPivot) Após clicar na opção Exportar como Feed de Dados selecione a opção "abrir" que fica no fim da tela. Caso o tipo de extensão não esteja associado ao Excel, selecione abrir com -> Excel. (Figura Habilite 9 a – conexão Abrir de Feed dados M V T e c h | 88 com conforme Excel) Figura 10. SQL Server: Além do Conceito Blog Post Collection (Figura 10 – Habilitar conexão de dados) Na tela a seguir, marque a opção "Only Create Connection", caso queira apenas importar os dados neste momento. Por padrão, o Excel importa os dados para o PowerPivot e cria uma Table. Note que a opção "Add this data to the Data Model" está marcada. Isso indica que os dados serão importados para o PowerPivot. M V T e c h | 89 SQL Server: Além do Conceito Blog Post Collection (Figura 11 – Selecionar o tipo de importação) Por fim, acesse a guia PowerPivot e veja que o Data Model foi exportado para o Excel. M V T e c h | 90 SQL Server: Além do Conceito Blog Post Collection (Figura 12 – Dados exportados) CONCLUSÃO Este artigo mostra uma das muitas formas possíveis de gerar relatórios usando os dados das listas do SharePoint. Após importar os dados, fica bem fácil criar relatórios complexos e dinâmicos usando PowerPivot, Excel, PowerView e PowerMap. M V T e c h | 91 SQL Server: Além do Conceito Blog Post Collection Configurar envio de e-mail no SharePoint / SQL Server com o GMAIL Neste artigo irei mostrar como configurar o envio de e-mail através do SharePoint/SQL Server utilizando contas do gmail. A ideia do post é mostrar como configurar o relay para envio de e-mail em aplicações que não suportam autenticação smtp. Alguns exemplos de ferramentas são Reporting Services, ArcServe Backup, SharePoint, etc.. Para estas aplicações a configuração de e-mail não é possível através de contas que requerem autenticação para enviar mensagens. Bem, vamos lá. Para realizar esta configuração nós precisamos configurar o relay de e-mails no Windows Server através do IIS, usando SMTP Server: P ASSO 1: C ONFIGURAR O SMTP S ERVER NO W INDOWS 2008. No Server Manager, vá em Add Features: M V T e c h | 92 SQL Server: Além do Conceito Blog Post Collection Na guia seguinte, escolha SMTP Server e deixe todas as configurações padrão: Confirme para adicionar os serviços necessários: M V T e c h | 93 SQL Server: Além do Conceito Blog Post Collection Deixe as demais opções com o valor padrão e clique em next até a aba final onde tem a opção de instalar. Após instalado, feche o Server Manager e abra o IIS 6.0: Menu iniciar / IIS / Enter. Com o IIS aberto, expanda o nó Local Computer e clique em propriedades do SMTP Virtual Server: Vá na guia access e clique em Relay: M V T e c h | 94 SQL Server: Além do Conceito Blog Post Collection Configure os PCs liberados para enviar e-mails através deste Relay. No meu caso, liberei para todos da rede: M V T e c h | 95 SQL Server: Além do Conceito Blog Post Collection Salve, volte para a guia propriedades e acesse a guia Delivery: M V T e c h | 96 SQL Server: Além do Conceito Blog Post Collection Clique em Outbound Security e selecione a opção Basic Authentication. Informe seu e-mail do Gmail, senha e marque a opção TLS: M V T e c h | 97 SQL Server: Além do Conceito Blog Post Collection Novamente no menu Delivery, acesse a opção Outbound Connections e mude a porta para 587 conforme abaixo e clique em OK: M V T e c h | 98 SQL Server: Além do Conceito Blog Post Collection Mais uma ves no menu Delivery, selecione a opção advanced e em Smart Host informe o SMTP do Gmail e clique em OK: Feche a tela clicando em OK e reinicie o IIS: M V T e c h | 99 SQL Server: Além do Conceito Blog Post Collection Para testar no SharePoint, abra a Central Admin do Sharepoint e Acesse o menu System Settings e na guia Outgoing E-mail Settings configure conforme abaixo: Pronto. Após isso seu SharePoint está pronto para enviar e-mails de notificações para listas, etc. M V T e c h | 100 SQL Server: Além do Conceito Blog Post Collection Marcel Inowe 4sqlserver.wordpress.com Dicas sobre o banco de dados do Protheus(Totvs) Olá pessoal, Esses dias meu amigo Leandro Ribeiro (http://www.sqlleroy.com |@sqlleroy) solicitou no Twitter dicas sobre o banco de dados do Protheus e como eu dou manutenção no banco de dados desse produto, percebi que eu sabia vários detalhes que poderiam ser úteis para quem está começando a trabalhar com o Protheus agora. Para quem não conhece o Protheus é um dos maiores ERPs do mundo, ele é desenvolvido pela empresa brasileira Totvs onde há alguns anos é líder de mercado nacional. A grande vantagem do Protheus é que além dele ser bem completo ele customizável, ou seja, você compra a licença do sistema e pode contratar um desenvolvedor para customizá-lo a seu gosto, já imaginou isso? Já pensou se você pudesse fazer isso com qualquer software que comprasse ou utilizasse? Pois é, por aí dá para sentir o poder do produto e dá para começar a perceber o porque ele é tão usado no mercado nacional, mas é claro que nem tudo são flores e é obvio que esse produto tem seus pontos fracos, algumas particularidades e é exatamente para discutir isso que escrevi esse post. V AMOS AS DICAS : Quase sempre o banco de dados se chama DADOSADV ou pelo menos começa com DADOS. Não me pergunte o motivo, pois eu não sei; A aplicação não acessa o banco de dados diretamente ela usa uma camada intermediária chamada Top Connect. O Top Connect quase sempre é instalado no mesmo servidor que o banco de dados, porém há casos em que ele é instalado em uma máquina exclusiva e então a aplicação se conecta ao Top e o Top se conecta ao SQL Server; M V T e c h | 101 SQL Server: Além do Conceito Blog Post Collection O Protheus é multiempresa, porém ao contrário do que estamos acostumado a ver nas modelagens onde a empresa é identificada com um campo dentro de cada tabela, o banco do Protheus cria uma tabela para cada empresa até a versão 10 do ERP, então se o teu cliente tiver mais de uma empresa aberta trabalhando no mesmo banco de dados, para cada empresa terá uma tabela de cliente, produto, nota fiscal e assim suscetivamente. Agora imaginem uma construtora do ramo imobiliário que para cada incorporação construída tem que ser aberto um CNPJ. Já pensou se ela tiver mais de 100 empreendimentos construídos ou em construção? O banco passará de 100 mil tabelas facilmente! A partir da versão 11 do Protheus já é possível criar as empresas dentro da mesma tabela o que diminui significativamente o número de tabelas dentro do banco de dados. Essa dica da versão 11 do Protheus foram dadas pelos amigos Bruno e Luiz Carlos nos comentários do post. O nome das tabelas não ultrapassam 6 caracteres e são representados da seguinte maneira: 3 primeiros caracteres é a família que aquela tabela pertence, os 2 próximos caracteres representa a empresa que aquela tabela pertence e o último caractere é reservado ao sistema, por exemplo a tabela de cliente da empresa 01 é a SA1010, da empresa 02 é a SA1020 onde SA1 é a família da tabela, 01 e 02 representa a empresa e o 0 no final é reservado. Como assim família ? Exemplo, cliente é SA1, fornecedor é SA2 e assim por diante. A Totvs considera que Cliente e Fornecedor pertencem à mesma família; O campo chave primária das tabelas é sempre o mesmo, ou seja, todas as tabelas tem um campo chamado R_E_C_N_O_ que é auto-incrementado pelo Top Connect e é a PK das tabelas; Os registros das tabelas nunca são deletados fisicamente. Todas as tabelas contém um campo chamado D_E_L_E_T_ e quando alguém excluí um registro no sistema, no banco de dados esse campo é preenchido com um *, então sempre que for fazer qualquer select lembrem-se de desprezar os registros deletados colocando na condição where D_E_L_E_T_ = ”, ou D_E_L_E_T_ <> ‘*’. Esse conceito de exclusão lógica foi herdado do DBF; M V T e c h | 102 SQL Server: Além do Conceito Blog Post Collection Não existe campo DateTime nas tabelas. Todos os campo data são VARCHAR(8), nunca são nulos e são sempre preenchidos com 8 caracteres em branco para informar que estão vazios; Não existe campo NULL. Se o campo for numérico ele é preenchido com zero e se for String/Char é preenchido com espaços em branco. Em ambos os casos o preenchimento é feito via Constraint Default. Agora imaginem a quantidade de Constraint que cada tabela tem!; Muito cuidado ao criar índices nas tabelas, pois se você criar em uma terá que criar em todas, por exemplo: Se criar um índice na tabela de cliente SA1XX0 lembre-se de replicar esse índice para as demais tabelas de cliente caso tenha; O Protheus trabalha com um dicionário de dados próprio onde são definidas as tabelas, campos e índices então em uma atualização de versão é feita uma checagem do dicionário de dados com a estrutura do banco de dados e tudo que não estiver definido no dicionário será apagado, seja campo, índice ou tabela, portanto ao criar um índice utilizado em um trabalho de Tuning eu aconselho a criar uma rotina que diariamente verifica a existência desse índice e então caso não exista mais crie-o novamente. Eu costumo colocar tudo dentro do step de um job que diariamente consulta a sys.indexes pelo nome; Nunca crie um campo em uma tabela sem antes passar para o dicionário de dados do Protheus, pois ao abrir uma tela que use a tabela onde o campo foi criado, essa tela irá travar por não ter o campo no dicionário; O desempenho das consultas não são grande coisa, pois a maioria dos desenvolvedores Protheus não tem grandes habilidades e conhecimento sobre indexação, então é sempre bom dar uma checada nas consultas mais lentas e dar um help para a galera de desenvolvimento; Uma forma de ganhar espaço em disco com o banco do Protheus é usar a compressão de dados a nível de página caso o SQL Server seja Enterprise. Em testes realizados na tabela SB1(Produtos) com 28000 produtos, comprimindo apenas a tabela passou de 72 MB para 6 MB, ou seja, uma taxa de compressão de 91.66%; M V T e c h | 103 SQL Server: Além do Conceito Blog Post Collection Os bancos geralmente são enormes então é válido pensar em uma estratégia de particionamento das tabelas; Índices não usados e duplicados não é excessão e sim regra, então é válido analisar isso e repassar para os desenvolvedores. Nunca apague um índice sem antes apagar no dicionário, pois as telas fazem essa verificação também em sua abertura e caso não encontre no banco elas travarão; O Top Connect não funciona em cluster devido ao hardlock que é quem licencia o Protheus e como em alguns casos ele é instalado no mesmo servidor do banco de dados, não será possível colocar ele no Service and Application do Cluster e quando ocorrer um Failover será necessário reiniciar o servidor de licença que fica geralmente em outro servidor, senão ele não voltará ao ar e a aplicação não abrirá; Não é possível fazer uma replicação merge das tabelas, devido fato da replicação merge adicionar um campo de controle de unicidade chamado rowguid e caso tenha um campo na tabela do banco e não tenha no dicionário do Protheus isso causa sérios impactos. Mesmo que não houvesse o impeditivo do campo rowguid, muitas tabelas ultrapassam 246 colunas e seria impossível replicar com merge devido o limite de 246 colunas por artigo; Devido o padrão das tabelas do Protheus não terem campos NULL e todos serem preenchidos com uma Constraint Default isso impede que as tabelas sejam colocadas In-Memory a.k.a Hekaton que é o novo recurso do SQL Server 2014. É possível desde que todas as Constraints Defaults sejam excluídas e os campos que são Not Null passem a ser Null, porém isso implicaria em uma grande mudança na modelagem do banco e os efeitos colaterais nesse tipo de mudança são incontáveis; Normalmente os bancos são muito grandes, então a rotina de manutenção de índices se torna uma tarefa difícil e quase impossível para a rotina do Maintenance Plan do SQL Server, portanto é válido usar rotina própria ou de terceiros como a rotina do Ola Hallengren. Bom galera espero que essas dicas sejam úteis para todos. Conforme eu for me lembrando de mais coisas eu vou atualizando o post. *Leandro Ribeiro | blog: sqlleroy.com | twitter: @sqlleroy M V T e c h | 104 SQL Server: Além do Conceito Blog Post Collection Marcos Freccia marcosfreccia.wordpress.com Importando arquivos excel usando o SSIS Olá pessoal, Hoje recebi uma dúvida do amigo Raphael Wanderley (@raphaelwsantos) sobre como importar um arquivo do Excel para o SQL Server. Na oportunidade eu mencionei a ele para utilizar o SQL Server Integration Services (SSIS), pois é muito mais simples de ser feito. Então, abaixo vou demonstrar como realizar a importação de arquivos utilizando o SSIS. Crie um novo projeto do tipo “Integration Services Project” conforme a imagem abaixo. M V T e c h | 105 SQL Server: Além do Conceito Blog Post Collection Você deverá agora arrastar o componente “Data Flow Task”, pois é dentro desse passo que vamos adicionar as fontes e destinos para realizar a cópia. De um duplo clique no componente e uma nova aba irá aparecer. Expanda a area Other Source e arraste o componente “Excel Source”. Expanda a area Other Destinations e arraste o componente “OLE DB Destination”. Por fim, conecte através da linha azul os dois componentes conforme a imagem abaixo. M V T e c h | 106 SQL Server: Além do Conceito Blog Post Collection De um duplo clique no componente “Excel Source” e depois crie uma nova conexão. Escolha o caminho do arquivo Excel que deseja importar, qual a versão do seu arquivo Excel e também se a primeira linha do documento contém as colunas e não dados. Para trabalhar com a arquitetura 64bit, você deve realizar o download do Microsoft Access Database Engine 2010 Redistributable. Baixe a versão 64bit M V T e c h | 107 SQL Server: Além do Conceito Blog Post Collection O próximo passo é escolher qual aba (Sheet) você deseja importar. Agora, de um duplo clique em “OLE DB Connection Manager” e clique em New para criar a conexão com o banco de dados. Crie a conexão com o banco de dados e confirme a operação. M V T e c h | 108 SQL Server: Além do Conceito Blog Post Collection Enquanto configura o destino dos seus dados, você tem a opção de escolher uma tabela já existe, ou criar uma nova tabela para receber os dados a serem importados. Neste exemplo vamos criar uma nova tabela. M V T e c h | 109 SQL Server: Além do Conceito Blog Post Collection Feito a criação da tabela, você já estará pronto para realizar a importação do arquivo. Agora, você poderá iniciar a execução do pacote pressionando a tecla F5 ou pressionando o botão conforme a imagem abaixo. O pacote sendo executado com sucesso, você deverá ver isso no fluxo criado. M V T e c h | 110 SQL Server: Além do Conceito Blog Post Collection Verificando o SQL Server, os arquivos foram importados corretamente. Pronto, você já fez a sua primeira solução em SSIS. Agora basta você seguir um tutorial de como agendar pacotes do SSIS no SQL Server Agent. M V T e c h | 111 SQL Server: Além do Conceito Blog Post Collection Espero que tenham gostado e estarei montando mais tutoriais desse tipo explicando pequenas funcionalidades. M V T e c h | 112 SQL Server: Além do Conceito Blog Post Collection T-SQL no SQL Server 2012 – Parte 1 Olá pessoal, O intuito dessa série de posts que vou iniciar agora é mostrar tudo de novo que temos na parte de T-SQL no SQL Server 2012. Antes de iniciarmos é bom deixar frisado que o intuito aqui não é mostrar nada mirabolante, mas sim o SIMPLES! Então esqueçam de ver algo avançado, o que vocês irão ver aqui é o básico. Para não criar posts extensos que nos cansam de ler, vou fazê-lo por partes. Hoje vamos falar de: Execute WITH RESULT SETS Sequence 1) EXECUTE WITH RESULT SETS. Esse novo recurso surgiu no SQL Server 2012 como uma necessidade de formatação de nossos conjuntos de dados, provenientes de uma stored procedure. Então sua explicação e demonstração é bastante simples. Pegamos um result set que está vindo como saída de uma procedure e mostramos para o usuário da maneira que necessitamos através desse result set personalizado. V AMOS VER COMO FUNCIO NA ? Tenho aqui uma simples procedure. USE AdventureWorksDW2012 GO CREATE PROCEDURE spGetSalesAmout AS SELECT FirstName , SalesAmount FROM FactInternetSales AS fact JOIN DimCustomer AS cust fact.CustomerKey = cust.CustomerKey M V T e c h | 113 ON SQL Server: Além do Conceito Blog Post Collection Temos aqui duas possibilidades de deixar nosso result set mais amigável. 1) Mudar diretamente no código T-SQL 2) Utilizar o recurso WITH RESULT SETS. Vamos ver como funciona? execute spGetSalesAmout WITH RESULT SETS ( ([Primeiro Nome] varchar(20), [Total de Vendas] money) ); Como vemos aqui, podemos até trocar o tipo de dados que será retornado. Vamos agora ver o resultado. M V T e c h | 114 SQL Server: Além do Conceito Blog Post Collection Em questões de usabilidade esse recurso seria interessante onde não podemos mudar o código da consulta T-SQL, por muitas vezes estar capturando dados de outros sistemas. Como podemos ver um recurso muito simples e que pode nos ajudar bastante. 2) SEQUENCE Recurso esse muito conhecido no Oracle é a sequence, um objeto responsável por gerar números sequencias. Ai você me pergunta: Mas já M V T e c h | 115 SQL Server: Além do Conceito Blog Post Collection temos o identity. Correto, porem o objeto Sequence vem para abrir mais possibilidades de utilização e como a mesma é um objeto permite outros tipos de gerenciamento que não temos no campo identity. C OMO UTILIZAR ? P ASSO 1: C RIAÇÃO DA S EQUENCE . A criação da sequence é muito simples e com apenas alguns comandos já conseguimos criar. CREATE SEQUENCE DemoSequence START WITH 1 INCREMENT BY 1; Até ai também podemos utilizar o identity no campo, já que conseguimos ter o início e realizar incrementos personalizados. C OMO UTILIZAMOS A SEQUENC E ? CREATE TABLE Demo1 ( id INT PRIMARY KEY , nome VARCHAR(100) ) GO INSERT INTO Demo1 VALUES ( NEXT VALUE FOR dbo.DemoSequence, 'Marcos Freccia' ) O comando NEXT VALUE FOR dbo.DemoSequence é o que faz o número ser gerado e automaticamente incrementado. M V T e c h | 116 SQL Server: Além do Conceito Blog Post Collection Se realizarmos mais uma inserção teremos. Como eu disse anteriormente, a Sequence é um objeto então a possibilidade de gerenciamento e de usabilidade é maior por exemplo. INSERT INTO Demo1 VALUES ( NEXT VALUE FOR dbo.DemoSequence + 2, 'Marcos Freccia' ) M V T e c h | 117 SQL Server: Além do Conceito Blog Post Collection R ESULTADO . Podemos criar também sequences que possuem um limite máximo de números a serem gerados. CREATE SEQUENCE DemoSequence2 START WITH 1 INCREMENT BY 1 MAXVALUE 5; Vamos realizar apenas uma demonstração. CREATE TABLE Demo2 ( id INT, nome VARCHAR(100) ) GO INSERT INTO Demo2 VALUES ( NEXT VALUE FOR dbo.DemoSequence2, 'Marcos Freccia' ) GO 5 SELECT FROM * Demo2 M V T e c h | 118 SQL Server: Além do Conceito Blog Post Collection Vamos realizar apenas mais uma inserção. Como puderam ver, a nossa sequence não deixou que realizássemos mais inserções de dados no campo. Bom pessoal por hoje era isso, espero que tenham gostado e no decorrer do tempo estarei mostrando mais funcionalidades em T-SQL no SQL Server 2012. M V T e c h | 119 SQL Server: Além do Conceito Blog Post Collection T-SQL no SQL Server 2012 – Parte 2 – Paginação de dados Olá pessoal, Atualmente aplicações web fazem o uso de uma funcionalidade até então presente apenas a nível de desenvolvimento que é o recurso de realizar a paginação dos dados, ou seja, mostrar dados em tela pouco a pouco e não simplesmente retornar tudo, assim evitando problemas de performance. Foi pensando nisso que no SQL Server 2012 foi implementado um novo recurso juntamente a clausula Order By utilizando dois recursos de nome OFFSET e FETCH. Para iniciarmos o entendimento sobre essa funcionalidade, precisamos ter em mente dois termos que serão utilizados na clausula Order By. OFFSET: Especifica o número de linhas a ignorar antes de iniciar o retorno dos dados propostos pela consulta. Esse valor sempre deverá ser maior ou igual a 0(zero) FETCH: Especifica o número de linhas a retornar depois que a clausula OFFSET foi processada. Esse valor sempre deverá ser um inteiro constante ou uma expressão que é maior ou igual a 1. Bom, vamos parar com a parte teórica e vamos demonstrar a parte pratica dessa nova função. Apenas alguns scripts de criação de base de dados e inserção de dados. USE master GO CREATE DATABASE DB_OrderByClause GO USE DB_OrderByClause GO CREATE TABLE tblPaginacao ( id INT IDENTITY , M V T e c h | 120 SQL Server: Além do Conceito Blog Post Collection nome VARCHAR(100) ) GO INSERT VALUES INTO tblPaginacao ( 'Registro 1' ),( 'Registro 2' ), ( 'Registro 3' ),( 'Registro 4' ), ( 'Registro 5' ),( 'Registro 6' ), ( 'Registro 7' ),( 'Registro 8' ), ( 'Registro 9' ),( 'Registro 10' ), ( 'Registro 11' ),( 'Registro 12' ), ( 'Registro 13' ),( 'Registro 14' ), ( 'Registro 15' ),( 'Registro 16' ), ( 'Registro 17' ),( 'Registro 18' ), ( 'Registro 19' ),( 'Registro 20' ) C ONSULTA 1 SELECT * FROM tblPaginacao ORDER BY id OFFSET 5 ROWS M V T e c h | 121 SQL Server: Além do Conceito Blog Post Collection Na primeira consulta apenas a clausula OFFSET foi especificada, ou seja, como foi falado anteriormente o OFFSET ignora o número de linhas desejadas. No exemplo estamos realizando o OFFSET de 5 registros, então é normal que a consulta seja retornada a partir do registro de número 6. C ONSULTA 2 SELECT * FROM tblPaginacao ORDER BY id OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY M V T e c h | 122 SQL Server: Além do Conceito Blog Post Collection Nessa segunda consulta foi especificado a clausula OFFSET e FETCH, ou seja, de acordo com a consulta será ignorada os cinco primeiros registros e apenas irá retornar os próximos dez registros, por isso a clausula FETCH NEXT 10 ROWS ONLY. Bom pessoal como vocês puderam ver apenas duas demonstrações básicas de como utilizar esse novo recurso no SQL Server 2012. Espero que tenham gostado e até a próxima. M V T e c h | 123 SQL Server: Além do Conceito Blog Post Collection Ivan Lima www.ivanglima.com Inside The Machine – Introdução Quando você pensa na memória do seu servidor, qual é a primeira coisa que te vem à cabeça? Gigabytes? Terabytes? Enfim, espaço? E quando você pensa em desempenho, a primeira coisa que você pensa são os Gigahertz da CPU? Nessa série de artigos vamos explorar o subsistema de memória de um ponto de vista um pouco diferente: o foco será a interação entre ele e a CPU. Falaremos do desempenho da memória e como ela pode afetar – e afeta! – o desempenho como um todo do seu servidor, e o que você pode – e não pode – fazer a respeito em relação ao seu banco de dados (ou qualquer outra aplicação). V ELOCIDADE DO PROCE SSADOR É TUDO ? Se você não conhece Martin Thompson, recomendo adicionar o blog ao seu leitor de RSS favorito e acompanhar o que ele escreve e palestra. Ele é definitivamente uma das grandes referências no assunto de HPC (High Performance Computing) e baixa latência e vamos utilizar alguns testes escritos por ele (e alguns meus) durante essa série, então nada mais justo do que começar fazendo referência a uma frase sua: “The real design action is in the memory sub-systems.” [2] Você já percebeu que ultimamente têm sido bastante falado sobre a velocidade dos processadores e como seu desempenho parou de evoluir nos últimos anos em favor do aumento da quantidade de cores? Quem desenvolve software com certeza já ouviu que deve aprender desenvolvimento de software com paralelismo para não arriscar ficar sem emprego no futuro. A famosa frase “the free lunch is over” tem sido repetida diversas vezes nas últimas conferências mundo à fora desde que o guru de M V T e c h | 124 SQL Server: Além do Conceito Blog Post Collection C++ Herb Sutter escreveu o seu artigo homônimo em 2005 para o respeitado journal Dr. Bobb’s [1]. De fato a frequência dos processadores parou de subir, principalmente devido às questões de economia de energia e dissipação de calor, como é possível observar claramente no gráfico abaixo tirado do artigo de Sutter: M V T e c h | 125 SQL Server: Além do Conceito Blog Post Collection Intel CPU Trends 1970-2010. Fonte: The Free Lunch Is Over, Herb Sutter Mas olhar apenas para os GHz não conta toda a história. Linha Modelo Ops/Sec Ano de Lançamento Core 2 Duo P8600 @ 2.40GHz 1434 2008 Xeon E5620 @ 2.40GHz 1768 2010 Core i7 i7-2677M @ 1.80GHz 2202 2011 Core i7 i7-2720QM @ 2.20GHz 2674 2011 Podemos observar na tabela acima que o desempenho geral do CPU continua subindo, mesmo que a frequência esteja, de certa forma, estagnada. Medimos esse desempenho através de IPCs, ou Instructions per Cycle. Ou seja, em um processador de 2 GHz capaz de fazer o retirement de até 4 instruções por ciclo (IPC), como é o caso da microarquitetura Nehalem, no caso ideal o seu desempenho pode chegar a 8 bilhões de instruções por segundo! Nada mal. M V T e c h | 126 SQL Server: Além do Conceito Blog Post Collection Single Threaded Performance Trends 1995-2011 [3] M V T e c h | 127 SQL Server: Além do Conceito Blog Post Collection Então se o desempenho das CPUs efetivamente continua subindo (apesar de claramente em um ritmo menor) mesmo que os clocks se mantenham estáveis, quem é o responsável por segurar o desempenho geral dos sistemas? Refazendo a pergunta anterior de outra forma… Em um workload onde o gargalo não se encontra nem em I/O nem na CPU, o que impede o seu processador de realizar o trabalho mais rapidamente? Você provavelmente já deve ter matado a charada: no acesso à memória, ou o que chamamos de latência. Mas esse fato não parece ser muito óbvio à primeira vista: memória não é só uma questão de quantidade. putz... Em relação ao custo de acesso ao disco, a latência do acesso à memória é irrisório. A memória, porém, é o que previne que o seu sistema rode em seu desempenho máximo. Isso ocorre pois o acesso à memória é significativamente inferior à velocidade do processador, e essa diferença só cresceu ainda mais nas últimas décadas. Esse fenômeno é chamado de “Memory Wall“, termo cunhado no paper [4]. Se pudéssemos trabalhar com dados apenas nos registradores, a “memória” com a menor latência no CPU, o nosso processador poderia utilizar todo o seu potencial computacional. Infelizmente, principalmente em servidores de bancos de dados, isso está muito longe da realidade. É comum trabalharmos com working sets de dezenas ou centenas de GB. E por isso pagamos o custo de acesso à memória o tempo todo. Enquanto esse acesso ocorre, o processador precisa ficar esperando pelos dados até que ele possa voltar a trabalhar, efetivamente gastando ciclos de clock à toa. Um cache miss pode custar centenas de ciclos de clock do processador, tempo que ele poderia gastar realizando operações ao invés de esperar por dados para serem processados. Com o fim da era de crescimento contínuo dos clocks dos processadores os engenheiros têm evoluído as microarquiteturas a fim de amenizar o impacto da latência do acesso à memória principal do sistema. Os processadores se utilizam de diversos artifícios para esconder essa latência, e assim diminuir a penalidade causada pela disparidade entre o desempenho entre eles. Um deles é o Hyper-Threading (SMT), tópico de um próximo artigo. REFERÊNCIAS: [1] Sutter – The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software [2] Thompson – Mythbusting modern hardware to gain “Mechanical Sympathy” [3] Moore – Data Processing in Exascale-class Computing Systems [4] Wulf, McKee – Hitting the Memory Wall: Implications of the Obvious M V T e c h | 128 SQL Server: Além do Conceito Blog Post Collection Inside the Machine – Processadores INTRODUÇÃO Se você não viu a primeira parte da série, sugiro que leia antes de continuar, pois nessa parte vamos seguir a linha de pensamento apresentado anteriormente. P ROCESSADORES Já que vamos falar sobre mecanismos internos das CPUs precisamos escolher alguma implementação, ou microarquitetura específica como ponto de partida. Escolhi a microarquitetura Nehalem [1] pelo simples fato de que tenho processadores baseados nessa microarquitetura tanto nos servidores do ambiente onde trabalho quanto no meu notebook. Segundo a Intel, o desenvolvimento dessa microarquitetura custou aproximadamente 12 bilhões de dólares, incluindo US$ 9 bilhões na construção das fábricas (fabs), US$ 1 bilhão para o design do processo de fabricação de 45 nanômetros em material dielétrico “High-k” [11], e US$ 2 bilhões no design da microarquitetura em si [3]. Outra microarquitetura, chamada Westmere é a versão reduzida (shrink) da microarquitetura Nehalem, seguindo o padrão tick-tock de fabricação da Intel [2]. Esse tem um processo de fabricação de 32nm. A atualização das fabs para esse shrink custou à Intel mais US$ 7 bilhões [10]. Apesar da Intel já ter lançado novas microarquiteturas desde então – Sandy Bridge, Ivy Bridge e o recémanunciado Haswell – as microarquiteturas Nehalem e Westmere são bastante comuns nos servidores que se encontram em produção hoje. O VERVIEW DA M ICROARQUITETURA Nehalem foi uma microarquitetura particularmente importante em relação a tecnologias Intel. Foi nessa microarquitetura que a Intel reintroduziu o hyper-threading ao seus processadores, após remover a funcionalidade nos processadores baseados na microarquitetura Core. Outra tecnologia importante introduzida pelo Nehalem foi o uso de um interconnect entre os processadores, similar ao que a AMD já vinha oferecendo, para remover o gargalo do acesso à memória com o Front-Side Bus (FSB). Chamado de QuickPath Interconnect (QPI), a Intel criou a tecnologia visando recuperar o mercado perdido para a AMD durante o período. Falaremos sobre o QPI no futuro, quando entrarmos no assunto de Non-Uniform Memory Access, ou NUMA. M V T e c h | 129 SQL Server: Além do Conceito Blog Post Collection Primeiro chip Nehalem, Cortesia Intel C ORE E U NCORE Na terminologia dos designers e engenheiros de processadores, os processadores são divididos entre Cores e Uncore. Cores são desenhados como blocos reutilizáveis de lógica e hardware e não mudam entre um modelo e outro. Os cores Nehalem e Westmere possuem 64 KB de cache L1 e 256 KB de cache L2 cada. O cache L3 é compartilhado entre todos os caches do chip, e o seu tamanho é dependente dos modelos. O Uncore, por outro lado, são os componentes que não fazem parte do Core. Dependendo da literatura que você ler isso inclui L3, I/O, IMC e QPI. Outros separam os componentes, portanto teríamos Uncore, QPI, IMC, etc. O Uncore pode mudar (e efetivamente muda) de um modelo para outro, mesmo entre modelos da mesma microarquitetura. P LANTA Além disso, os Cores rodam em frequências e voltagens independentes entre si. O Uncore também roda em uma frequência independente do restante dos cores. Nos slides da Intel, eles se referem ao Uncore e outros componentes de forma distinta, mas ao se referirem à frequência e voltagem, chamam todos de Uncore também. M V T e c h | 130 SQL Server: Além do Conceito Blog Post Collection Particionamento de voltagem e frequência do Nehalem, Cortesia Intel A diferença na frequência entre Cores e Uncore tem impacto direto no desempenho da máquina, através de funcionaliades como Turbo Boost e SpeedStep. Quando estiver abordando um assunto específico de cada modelo (uncore) darei preferência ao Xeon E78870, o modelo com qual trabalho. Conhecido como Westmere-EX, este é o absoluto top de linha da Intel em arquitetura x86 nesse ciclo de lançamentos. X EON E7 O Xeon E7-8870 possui aproximadamente 2.6 bilhões (!) de transístores em uma pastilha de 513 mm²; quatro portas QuickPath Interconnect (fullwidth) em 3.2 GHz rodando a 25.6 GB/s full-duplex; 2 controladoras de memória DDR3 on-chip dual-channel de 10.83 GB/s cada, totalizando 4 canais e 43.3 GB/s; 10 cores – 20 threads em com hyper-threading – por socket rodando a uma frequência base de 2.4 GHz. As 4 portas QPI permitem escalar até 8 sockets em um único sistema e chegar até 2 TB de memória com DIMMs de até 32 GB. Processador Intel Xeon E7, Cortesia Intel M V T e c h | 131 SQL Server: Além do Conceito Blog Post Collection Chip Westmere, Cortesia Intel Note o aumento de cores na imagem do chip Westmere em relação ao Nehalem apresentado no início do post. Se olhar atentamente, poderá perceber que se tratam dos mesmos cores, apenas replicados mais 2 vezes. É possível perceber também o aumento nos bancos de cache, abaixo dos cores. C ORE I 5 460M Já o meu notebook tem uma configuração bem mais modesta e é organizado de uma forma um pouco diferente, apesar de ser baseado na mesma microarquitetura. É um Intel Core i5 460M, codinome Arrendale, rodando a 2.53 GHz. Possui aproximadamente 382 milhões de transístores divididos entre 2 cores e o LLC (aka L3) de 4 MB, porém somente 3 MB são habilitados para esse modelo. A controladora de memória (IMC) e o gráfico ficam em outro chip no mesmo package, interligados com o chip do processador através de uma interface QuickPath Interconnect. A controladora de memória possui 2 canais DDR3 de 1.333 MHz e suportam DIMMs de até 8 GB. Na imagem abaixo podemos visualizar o chip do processador (88mm²) e o chip “Northbridge” de aprox. 177 milhões de transístores (114mm²) no mesmo package. Intel’s Core i5 Arrandale CPU, Cortesia Intel No diagrama de blocos podemos ver claramente a topologia entre o processador e o GPU, conectados por uma interface QPI: M V T e c h | 132 SQL Server: Além do Conceito Blog Post Collection Diagrama de blocos dos Clarkdale/Arrandale, Cortesia Arstechnica M OORE ’ S L AW Como eu falei no artigo anterior o clock dos processadores parou de subir mas o desempenho dos cores continua subindo, embora não no mesmo ritmo que subia anteriormente. Como isso é possível? Através da lei de Moore. Gordon Moore [4] é co-fundador da Intel, e a lei leva o seu nome pois ele foi o autor da frase que dizia que o número de transistors em cada processador dobraria a cada 2 anos. Existem diversas versões e interpretações das palavras ditas por Moore. Segue a frase original [5]: “The complexity for minimum component costs has increased at a rate of roughly a factor of two per year. Certainly over the short term this rate can be expected to continue, if not to increase. Over the longer term, the rate of increase is a bit more uncertain, although there is no reason to believe it will not remain nearly constant for at least 10 years.” A frase pode se encontrada no artigo escrito por Moore [14], mas sem entender a relação entre defeitos, custo e integração na fabricação de chips a frase é difícil de ser digerida. Uma versão que gosto e que modifica ao mínimo a frase foi publicada no Arstechnica, em 2008 [13]: “The number of transistors per chip that yields the minimum cost per transistor has increased at a rate of roughly a factor of two per year.” Esse é o sentido original da frase, e a percepção do mercado de chips em geral nas últimas décadas. A frase foi dita em 1965, e apesar de Moore ter previsto a continuidade por 10 anos, a lei continua em vigor até hoje. M V T e c h | 133 SQL Server: Além do Conceito Blog Post Collection Gráfico do número de transístores ao longo da história, Cortesia Wikipedia M V T e c h | 134 SQL Server: Além do Conceito Blog Post Collection Essa quantidade extra de transístores é utilizada pelos engenheiros para aumentar a eficiência dos processadores. Com cada ciclo de lançamentos, os processadores ficam mais e mais complexos. Em alguns modelos Nehalem, por exemplo, quase 60% desses transístores são dedicados aos caches, principalmente no cache L3 [12]. O restante é utilizado para adicionar mais lógica e mais funcionalidades, aumentando assim a complexidade dos chips. C OMPLEXIDADE Vista aérea de Shangai, China Para se ter uma ideia da complexidade desses processadores, basta imaginar que a cidade mais populosa da China, Shangai, possui aproximadamente 16 milhões de habitantes, enquanto o processador Xeon E7-8870, como dito anteriormente, possui aproximadamente 2.6 bilhões de transístores. Ou seja, se cada morador correspondesse a um transístor, precisaríamos de 162 Shangais e meia. Isso é o dobro de toda a população da própria China, o país mais populoso do mundo. GPGPU Uma forma alternativa de utilizar esses transístores seria a criação de núcleos pouco complexos, porém em quantidades muito maiores do que vistos hoje, como por exemplo um processador com dezenas ou centenas de cores. Na verdade esse tipo de arquitetura existe e é muito utilizada. É encontrada em GPUs, que possuem centenas de núcleos simples (em relação aos núcleos de uma CPU). Em geral, esses núcleos não servem para fazer o processamento de qualquer tipo de código e operação e portanto não substituem os processadores comuns, mas podem ser úteis para algoritmos onde é possível fazer paralelismo massivo do processamento. Existem várias vertentes de desenvolvimento de dispositivos, linguagens e ferramentas para aproveitar melhor esses recursos como o NVIDIA CUDA, OpenCL e mais recentemente o C++AMP da Microsoft, do qual já falei no meu blog. Em (http://ivanglima.com/c-em-2012/) Esse tipo de processamento, chamado de General-purpose computing on graphics processing units, ou GPGPU, ainda não é utilizado pelos SGBDs, mas já existem pesquisas nesse sentido, como pode ser visto em [8] e [9]. C ACHE Agora que já fizemos uma introdução básica às CPUs, no próximo artigo vamos nos aprofundar um pouco no assunto dos caches. REFERÊNCIAS [1] [2] http://en.wikipedia.org/wiki/Nehalem_(microarchitecture) http://en.wikipedia.org/wiki/Intel_Tick-Tock M V T e c h | 135 SQL Server: Além do Conceito Blog Post Collection [3] http://forwardthinking.pcmag.com/pc-hardware/283044-intel-looks-ahead-nehalem-larrabee-and-atom [4] http://en.wikipedia.org/wiki/Gordon_Moore [5] http://en.wikipedia.org/wiki/Moore’s_Law [6] http://www.xbitlabs.com/articles/cpu/display/core-i7-920-overclocking_3.html [7] http://www.extremetech.com/extreme/133541-intels-64-core-champion-in-depth-on-xeon-phi [8] http://sacan.biomed.drexel.edu/vldb2012/program/?volno=vol5no13&pid=1004&downloadpaper=1 [9] http://wiki.postgresql.org/images/6/65/Pgopencl.pdf [10] http://asia.cnet.com/blogs/intel-invests-us7-billion-in-32nm-westmere-cpu-manufacturing62114335.htm [11] http://www.intel.com/pressroom/kits/advancedtech/doodle/ref_HiK-MG/high-k.htm [12] http://upcommons.upc.edu/e-prints/bitstream/2117/13932/1/hybrid_NUCA-hipc11.pdf [13] http://arstechnica.com/gadgets/2008/09/moore/ [14] http://www.computerhistory.org/semiconductor/assets/media/classic-paperspdfs/Moore_1965_Article.pdf M V T e c h | 136 SQL Server: Além do Conceito Blog Post Collection Inside The Machine - Hyper-Threading (SMT) e SQL Server O principal fator que vai definir o impacto do HT no seu ambiente é o seu workload – tanto positivamente quanto negativamente. A própria Intel limita o ganho teórico do HT a 30% [1]. Isso é, no melhor do melhor dos casos, o máximo de desempenho que você vai “ganhar” com HT é 30%. É pouco? Não acho. Mas o que eu acho é que HT é muitas vezes confundido como uma funcionalidade de desempenho quando na realidade é uma funcionalidade que visa melhorar a eficiência do seu processador. Ele vai utilizar alguns ciclos a mais que teriam sido perdidos caso não houvesse um “pipeline” substituto pronto para entrar em cena. Não há ganho, e sim “controle de perda”. HT nada mais é do que a duplicação de alguns componentes do pipeline do núcleo, permitindo que esse, no melhor caso, não pare totalmente de trabalhar quando houver uma dependência ainda não disponível durante a execução, como um acesso de memória que resultou em cache miss, por exemplo. Pipeline (SMT) M V T e c h | 137 SQL Server: Além do Conceito Blog Post Collection T EORIA E PRÁTICA Ok, mas saindo um pouco da teoria e indo para a parte prática, muitas coisas começam a influenciar na brincadeira. O próprio escalonamento do Windows (e de tabela o do SQL Server) afeta o desempenho do sistema com o HT habilitado ou não. Por exemplo, se o algoritmo do scheduler não levar em conta o fato de dois “núcleos lógicos” (por falta de nome melhor) compartilharem os mesmos ALUs o seu desempenho vai piorar sensivelmente quando o scheduler escalonar duas threads no mesmo núcleo físico ao invés de núcleos físicos distintos. Esse cenário era muito comum nos primórdios do Windows Server [2], quando este não fazia distinção entre núcleos físicos e lógicos. Ainda vemos algo parecido hoje nos processadores oriundos da microarquitetura Bulldozer da AMD, que utiliza uma tecnologia que também afeta o comportamento do pipeline, mas não é exatamente uma implementação do SMT. Os schedulers não estavam preparados para lidar com isso durante o lançamento dos processadores dessa microarquitetura, fazendo a AMD sofrer em alguns benchmarks [3]. Trocando em miúdos, existem muitos fatores e o impacto no desempenho final pode ser bem maior do que os 30% teóricos, tanto positivamente quanto negativamente. M ITO Existe um mito que o Hyper-Threading é o mal encarnado para o SQL Server, devido a diversos fatores, incluindo os citados acima. Um dos causadores (não intencional) desse rumor foi o Slava Oks [4] (ex-time de produto, SQLOS), e se você quiser ver um ótimo exemplo de como fazer o HT não funcionar, sugiro que leia o seu post e execute os testes você mesmo. P ROCESSADORES Agora vamos para a questão de desempenho de processadores… Observando o processo do SQL Server (sqlservr.exe) podemos notar que ele possui callstacks bastante profundas, de pelo menos uns 8 níveis desde o início do processamento de uma consulta, e muitos branches ao longo da execução dessa consulta, mesmo simples. Servidores OLTP, em geral, costumam ter um working set de GBs de dados em memória e processar pequenas partes dessa massa à cada segundo, de forma “aleatória”. Na teoria [5], esses tipos de cenários são excelentes candidatos a fazer um bom uso do SMT e também são bastante influenciados pelo tamanho dos caches do processador, a latência de acesso da sua memória RAM e a eficiência do branch predictor. Esses fatores podem até mesmo influenciar mais que o próprio clock do seu processador… Nada de comprar processadores olhando apenas os GHz! M V T e c h | 138 SQL Server: Além do Conceito Blog Post Collection Workloads de OLAP e aplicações científicas , por outro lado, tendem a ser mais sensíveis à “força bruta” do processador. Enfim… No final das contas, a única coisa que vai te dizer se o HT pode ou não beneficiar o seu ambiente é o teste. São fatores demais que influenciam no resultado final para fazer uma previsão para qualquer direção. Se você tiver um processador com HT, teste seu workload com e sem o HT habilitado e colete métricas que te dirão qual é preferível. No caso do seu processador não possuir a funcionalidade, só posso dizer que não se preocupe com isso. Há formas mais práticas e diretas de influenciar o desempenho do seu ambiente. REFERÊNCIAS: [1] http://en.wikipedia.org/wiki/Simultaneous_multithreading#Modern_commercial_implementations [2] http://www.hardwaresecrets.com/article/Activating-the-Hyper-Threading/20 [3] http://www.hardwarecanucks.com/news/cpu/microsoft-tries-again-second-win-7-bulldozer-hotfixnow-available/ [4] http://blogs.msdn.com/b/slavao/archive/2005/11/12/492119.aspx [5] http://www.cs.washington.edu/research/smt/papers/smtdatabase.pdf M V T e c h | 139 SQL Server: Além do Conceito Blog Post Collection Fabiano Neves Amorim www.blogfabiano.com Join reordering e Bushy Plans INTRODUÇÃO Normalmente o otimizador de consultas não considera “bushy plans” (dois operadores se unem ao resultado de outros joins). Isso significa que o SQL pode não produzir bons planos para alguns tipos de consultas. Hints (dicas), por si só também não irão fazer isso. Para tal otimização, uma mágica mais poderosa é necessária. J OIN REORDERING E B USHY P LANS Pessoal, atualmente estou sofrendo com meu conflito existencial de “otimizador sucks”, deixa eu explicar melhor. Quando você começa a trabalhar e estudar muito sobre o otimizador de consultas do SQL Server (ou de qualquer outro DB) você passa por vários conflitos existenciais, são eles: Olha se eu apertar ctrl+l aparece um monte de desenhinhos Preciso aprender a ler um plano de execução (já não chama mais de desenhinhos) Mas que raios esse operador faz? Por quê??? Mas por quê????? Conor Cunningham (http://blogs.msdn.com/b/conor_cunningham_msft/) é gente boa demais! Aaaaa, estou começando a entender Esse Paul White (http://sqlblog.com/blogs/paul_white/default.aspx) é insano! UAU! Que esperto que o otimizador é! Odeio esse Paul White (inveja pura!) Opa, estimou errado! Ummm, acho que dá pra melhorar esse plano! Ummm, acho que dá pra melhorar esse plano 2! Ummm, acho que dá pra melhorar esse plano 3! M V T e c h | 140 SQL Server: Além do Conceito Blog Post Collection Estatísticas sucks! Joins sucks! Otimizador sucks! ... Pois bem, eu estou no nível “otimizador sucks” . Não sei o que esta acontecendo (pode ser apenas uma fase), mas ultimamente 60% das consultas em que trabalho na otimização tem um plano de execução ruim. Ok, muitas vezes isso é culpa de um ser humano e não do otimizador, por exemplo, o DBA “esqueceu” de atualizar as estatísticas, ou o desenvolvedor escreveu algum non-sarg. Mas ainda assim temos os casos onde simplesmente a culpa é do otimizador, consultas onde ele deveria gerar um plano mais eficiente. Veja bem, eu não estou dizendo que isso é um problema ou bug do SQL Server, essa é uma limitação de todos os otimizadores existentes no mercado, a quantidade de alternativas para a geração de um plano pode ser tão grande que fica completamente impossível pro otimizador analisar todas as opções, eu entendo bem isso. O otimizador de consultas do SQL Server é baseado em framework chamado Cascades [2], e ele executa uma serie de explorações em uma consulta para tentar gerar um plano de execução “bom o suficiente” utilizando a menor quantidade de recursos possíveis e, no menor tempo possível. No SQL Server essas explorações são divididas em fases, e uma dessas fases é conhecida como “heuristic join reorder” onde o SQL tenta definir qual será a ordem inicial de execução dos joins. A grande dificuldade no processo de otimização de uma consulta é fazer isso na menor tempo possível, ou seja, preferencialmente o otimizador nunca pode levar mais tempo para otimizar uma consulta do que irá gastar para executar o plano. Isso pode parecer trivial, mas a quantidade de permutações possíveis para acessar uma consulta com 12 joins seria de aproximadamente 479 milhões e considerando bushy plans teríamos uma variação de 28 trilhões, ou seja, não da pra testar todas as possibilidades para qual é o melhor plano [5]. Dito isso, que fique claro que com este artigo não quero mostrar o quão ineficiente o otimizador de consultas do SQL Server é, ou o quanto ele “sucks”, mas quero mostrar que no mundo otimização de consultas, as coisas são sempre mais complicadas do que parecem . B USHY P LANS NO SQL S ERVER Há muitos anos eu tento criar um exemplo prático para falar sobre bushy plans (veja referencias no fim do artigo) no SQL Server. Em poucas palavras um bushy plan é uma das opções que o Otimizador tem para poder executar os joins de sua consulta. Para efetuar uma operação de join o otimizador considera algumas variações de execução de acesso as tabela e ordem de execução dos joins, essa ordem pode seguir um left-deep (onde o resultado do join é utilizado como outer input para o próximo join) ou right- M V T e c h | 141 SQL Server: Além do Conceito Blog Post Collection deep (onde o resultado do join é utilizado como inner input para o próximo join), ou um misto entre eles. (veja a imagem abaixo para visualizar o que estou querendo dizer) Atualmente o otimizador de consultas do SQL Server valida as opções que mencionei acima, porem existe outra possibilidade de ordem de leituras das tabelas que não é considerada por default, o bushy trees. Bushy trees podem ser interessantes em cenários em que o resultado de um join resulta em um filtro considerável do resultset do join, ou seja, você lê várias linhas, mas depois de fazer o join poucas são retornadas. Um bushy plan (um plano com uma bushy tree) é um plano que faz o join com base no resultado de outros dois joins. Deixa eu tentar ilustrar para ver se fica mais claro: Considerando o seguinte select: SELECT FROM JOIN JOIN JOIN * A B ON A.ID = B.ID C ON A.ID = C.ID D ON A.ID = D.ID Podemos ter os seguintes planos: A primeira árvore de joins contém um join em formato left-deep que executa os joins na seguinte ordem: JOIN( JOIN( JOIN(A, B), C), D) E a segunda árvore de joins contém o join em formato bushy que executa os joins na seguinte ordem: JOIN(JOIN(A, B), JOIN(C, D)) O otimizador do SQL Server não avalia a possibilidade de bushy trees porque ela poderia gerar milhões de possibilidades na ordem de execução dos joins, portanto para forçar a execução de um bushy plan no SQL M V T e c h | 142 SQL Server: Além do Conceito Blog Post Collection Server temos 2 opções, usando CTEs (que eu prefiro) ou com uma sintaxe pouco convencional pra fazer os joins, e ambas devem utilizar o hint FORCE ORDER. Pois bem agora que você entendeu um pouco sobre bushy plans, deixa eu te mostrar um exemplo prático de otimização que podemos ter. Suponha o seguinte cenário no banco Northwind, para criar este banco utilize o meu script do skydrive: http://sdrv.ms/VaTL6W Antes de começar os testes, vamos cadastrar um cliente novo e uma nova venda para este cliente: -- Inserir venda para novo cliente -- Cadastrar cliente "Fabiano Amorim" INSERT INTO CustomersBig (CityID, CompanyName, ContactName, Col1, Col2) VALUES (57, 'Empresa do Fabiano', 'Fabiano Amorim', NEWID(), NEWID()) -- Cidade 57 = Sao Paulo -- Cadastrar Venda INSERT INTO OrdersBig (CustomerID, OrderDate, Value) VALUES(SCOPE_IDENTITY(), GetDate(), 999) SET IDENTITY_INSERT Order_DetailsBig ON INSERT INTO Order_DetailsBig(OrderID, ProductID, Shipped_Date, Quantity) VALUES (SCOPE_IDENTITY(), 1, GetDate() + 30, 999) SET IDENTITY_INSERT Order_DetailsBig OFF GO Temos os seguintes índices: CREATE INDEX ixContactName ON CustomersBig(ContactName) -Indexando WHERE CREATE INDEX ixProductName ON ProductsBig(ProductName) -Indexando WHERE CREATE INDEX ixCustomerID ON OrdersBig(CustomerID) INCLUDE(Value) -- Indexando FK CREATE INDEX ixProductID ON Order_DetailsBig(ProductID) INCLUDE(Quantity) -- Indexando FK GO E seguinte consulta: -- Gerar "cold cache" CHECKPOINT; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO SELECT OrdersBig.OrderID, OrdersBig.Value, Order_DetailsBig.Quantity, CustomersBig.ContactName, ProductsBig.ProductName M V T e c h | 143 SQL Server: Além do Conceito Blog Post Collection FROM INNER ON INNER ON INNER ON WHERE AND GO OrdersBig JOIN CustomersBig OrdersBig.CustomerID = CustomersBig.CustomerID JOIN Order_DetailsBig OrdersBig.OrderID = Order_DetailsBig.OrderID JOIN ProductsBig Order_DetailsBig.ProductID = ProductsBig.ProductID CustomersBig.ContactName = 'Fabiano Amorim' ProductsBig.ProductName = 'Outback Lager 1EA81379' Consulta tem o seguinte plano: A performance é a seguinte: STATISTICS IO: Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0 Table 'OrdersBig'. Scan count 0, logical reads 11776, physical reads 1, read-ahead reads 11576 M V T e c h | 144 SQL Server: Além do Conceito Blog Post Collection Table 'Order_DetailsBig'. Scan count 1, logical reads 10, physical reads 1, read-ahead reads 14 Table 'ProductsBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Table 'CustomersBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Temos alguns problemas com relação a este plano, o primeiro e mais interessante é que por causa da ordem que os joins serão efetuados o seek na tabela OrdersBig será executado centenas de vezes, mais precisamente 2344 vezes, pois esse é o número de linhas que são retornados do join entre ProductsBig e OrderDetails_Big. Porém sabemos que existe apenas uma “order” para o cliente “Fabiano Amorim”, ou seja, eu esperava apenas uma operação de seek. Como em tempo de compilação do plano o SQL Server não sabe qual é o valor de CustomerID do cliente “”Fabiano Amorim” ele não consegue fazer a estimativa utilizando a estatística por OrdersBig.CustomerID. Ficou confuso? Deixa eu te mostrar com um exemplo mais simples, imagine a seguinte consulta: SELECT FROM INNER ON WHERE OrdersBig.OrderID, CustomersBig.ContactName OrdersBig JOIN CustomersBig OrdersBig.CustomerID = CustomersBig.CustomerID CustomersBig.ContactName = 'Fabiano Amorim' P LANO ESTIMADO : Repare que a estimativa de linhas que serão retornadas após o seek pelo “Fabiano Amorim” é de 1 linha, porém ao consultar a tabela de OrdersBig ele estima que 1250000.00 (um milhão duzentos e cinquenta) linhas serão retornadas, crazy ha? Pois este é um problema bem conhecido no mundo dos otimizadores, M V T e c h | 145 SQL Server: Além do Conceito Blog Post Collection em tempo de compilação da consulta o SQL Server não sabe qual é o valor que será retornado de CustomersBig.Contact_ID e por isso ele não consegue estimar corretamente, dai o que ele fez? Adivinha? Chutou que 30% da tabela será retornada, neste caso como a tabela tem 5 milhões de linhas, ele estimou um milhão duzentos e cinquenta linhas. Multi-Column Cross-Table Statistics ajudariam e muito neste cenário, mas ainda não temos isso no SQL Server. Outra forma de resolver isso seria criar uma estatística filtrada, mas isso não vem ao caso, fica pra outro post. UPDATE: O SQL não chutou não, ele usou a densidade para obter o valor com base na quantidade média de linhas duplicadas na distribuição dos dados. Deixe-me explicar melhor. sp_helpstats OrdersBig Na tabela OrdersBig temos uma estatística criada automaticamente pelo SQL Server, ou seja, ela foi criada como uma distribuição de exemplo dos dados na tabela (WITH SAMPLE). Vamos rodar um DBCC SHOW_STATISTICS para ver mais informações sobre ela: DBCC SHOW_STATISTICS(OrdersBig, _WA_Sys_00000002_5CA1C101) Para fazer a estimativa o SQL Server usa essa informação da densidade, ele estimou o seguinte, ele faz densidade * número de linhas da tabela, ou seja, 0.25 * 5000000 = 1250000, tai o valor estimado, coincidentemente esse valor é 30% da tabela o que me levou a acreditar nos 30% (my bad). M V T e c h | 146 SQL Server: Além do Conceito Blog Post Collection Na verdade a densidade da tabela é de 0.2 e não 0.25, se você atualizar a estatística com fullscan vera que o valor vai mudar, e consequentemente a quantidade de linhas estimadas será de 0.2000 * 5000000, ou seja, 100000 linhas. Bom voltando ao plano que estamos analisando, por que o SQL Server estimou que 1.250000 linhas seriam retornadas ele optou por não fazer o Join de CustomersBig + OrdersBig e isso está errado, sabemos que apenas 1 linha será retornada ele deveria ter feito o seek em CustomersBig e apenas 1 seek em OrdersBig. O mesmo se aplica para o join entre ProductsBig e Order_DetailsBig, porém neste caso o SQL estimou utilizando a densidade da coluna Order_DetailsBig.ProductID, dai os 2328 estimados (veja no plano estimado da consulta completa), só pra confirmar: -- Calculando densidade SELECT (1.0 / COUNT(DISTINCT ProductID)) FROM Order_DetailsBig -- Calculando estimativa com base na densidade SELECT ROUND(0.000465549348 * 5000000, 0) Temos: Neste caso estimar utilizando a densidade foi excelente, pois o número de linhas retornadas foi de 2344, ou seja, bem próximo do estimado que foi de 2328. A Fabiano, mas e o Bushy plan? Calma ai, vamos lá, sabendo que o Join entre CustomersBig + OrdersBig irá retornar 1 linha, e o join entre ProductsBig + Order_DetailsBig irá retornar 2344 linhas, podemos forçar a execução da seguinte ordem dos joins JOIN(JOIN(CustomersBig, OrdersBig), JOIN(ProductsBig, Order_DetailsBig)), vamos testar utilizando CTEs: -- Gerar "cold cache" CHECKPOINT; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO ;WITH JoinEntre_CustomersBig_e_OrdersBig AS ( SELECT OrdersBig.OrderID, OrdersBig.Value, CustomersBig.ContactName FROM CustomersBig M V T e c h | 147 SQL Server: Além do Conceito Blog Post Collection INNER JOIN OrdersBig ON OrdersBig.CustomerID = CustomersBig.CustomerID ), JoinEntre_ProductsBig_e_Order_DetailsBig AS ( SELECT Order_DetailsBig.OrderID, Order_DetailsBig.Quantity, ProductsBig.ProductName FROM ProductsBig INNER JOIN Order_DetailsBig ON Order_DetailsBig.ProductID = ProductsBig.ProductID ) SELECT JoinEntre_CustomersBig_e_OrdersBig.OrderID, JoinEntre_CustomersBig_e_OrdersBig.Value, JoinEntre_ProductsBig_e_Order_DetailsBig.Quantity, JoinEntre_CustomersBig_e_OrdersBig.ContactName, JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName FROM JoinEntre_CustomersBig_e_OrdersBig INNER JOIN JoinEntre_ProductsBig_e_Order_DetailsBig ON JoinEntre_CustomersBig_e_OrdersBig.OrderID = JoinEntre_ProductsBig_e_Order_DetailsBig.OrderID WHERE JoinEntre_CustomersBig_e_OrdersBig.ContactName = 'Fabiano Amorim' AND JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName = 'Outback Lager 1EA81379' OPTION (FORCE ORDER, MAXDOP 1) GO Temos o seguinte plano: M V T e c h | 148 SQL Server: Além do Conceito Blog Post Collection Como você pode observar, escrevendo as CTEs exatamente na ordem em que quero que os joins sejam executados e utilizando o hint force order, conseguimos o plano que faz um merge join entre o resultado dos dois joins. A performance é a seguinte: STATISTICS IO: Table 'Order_DetailsBig'. Scan count 1, logical reads 10, physical reads 1, read-ahead reads 14 Table 'ProductsBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Table 'OrdersBig'. Scan count 1, logical reads 4, physical reads 2, read-ahead reads 8 Table 'CustomersBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 M V T e c h | 149 SQL Server: Além do Conceito Blog Post Collection A diferença é enorme, a consulta com o BushyPlan roda em meio segundo, isso é 24 vezes mais rápido que a query original, porém essas duas operações de SORT (veja no plano) para fazer o Merge Join são de assustar, SORT é uma das operações mais pesadas para fazer no banco de dados, principalmente se o SORT for feito em disco. Para confirmar como esse sort é pesado, vamos fazer um teste utilizando um CustomerName que retorna mais Orders e outro ProductName, ou seja, mais linhas serão ordenadas. Query original sem bushy plan: -- Gerar "cold cache" CHECKPOINT; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO SELECT OrdersBig.OrderID, OrdersBig.Value, Order_DetailsBig.Quantity, CustomersBig.ContactName, ProductsBig.ProductName FROM OrdersBig INNER JOIN CustomersBig ON OrdersBig.CustomerID = CustomersBig.CustomerID INNER JOIN Order_DetailsBig ON OrdersBig.OrderID = Order_DetailsBig.OrderID INNER JOIN ProductsBig ON Order_DetailsBig.ProductID = ProductsBig.ProductID WHERE CustomersBig.ContactName = 'Karl Jablonski 1E663869' AND ProductsBig.ProductName = 'Ravioli Angelo D01AFCFC' GO 950 linhas são retornadas e a performance é: STATISTICS IO: M V T e c h | 150 SQL Server: Além do Conceito Blog Post Collection Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0 Table 'OrdersBig'. Scan count 0, logical reads 11702, physical reads 1, read-ahead reads 11664 Table 'Order_DetailsBig'. Scan count 1, logical reads 9, physical reads 2, read-ahead reads 6 Table 'ProductsBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Table 'CustomersBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Query com o BushyPlan: -- Gerar "cold cache" CHECKPOINT; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO ;WITH JoinEntre_CustomersBig_e_OrdersBig AS ( SELECT OrdersBig.OrderID, OrdersBig.Value, CustomersBig.ContactName FROM CustomersBig INNER JOIN OrdersBig ON OrdersBig.CustomerID = CustomersBig.CustomerID ), JoinEntre_ProductsBig_e_Order_DetailsBig AS ( SELECT Order_DetailsBig.OrderID, Order_DetailsBig.Quantity, ProductsBig.ProductName FROM ProductsBig INNER JOIN Order_DetailsBig ON Order_DetailsBig.ProductID = ProductsBig.ProductID ) SELECT JoinEntre_CustomersBig_e_OrdersBig.OrderID, JoinEntre_CustomersBig_e_OrdersBig.Value, JoinEntre_ProductsBig_e_Order_DetailsBig.Quantity, JoinEntre_CustomersBig_e_OrdersBig.ContactName, JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName FROM JoinEntre_CustomersBig_e_OrdersBig INNER JOIN JoinEntre_ProductsBig_e_Order_DetailsBig ON JoinEntre_CustomersBig_e_OrdersBig.OrderID = JoinEntre_ProductsBig_e_Order_DetailsBig.OrderID WHERE JoinEntre_CustomersBig_e_OrdersBig.ContactName = 'Karl Jablonski 1E663869' AND JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName = 'Ravioli Angelo D01AFCFC' OPTION (FORCE ORDER, MAXDOP 1) M V T e c h | 151 SQL Server: Além do Conceito Blog Post Collection GO 950 linhas são retornadas e a performance é: STATISTICS IO: Table 'Order_DetailsBig'. Scan count 1, logical reads 9, physical reads 2, read-ahead reads 6, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'ProductsBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'OrdersBig'. Scan count 1, logical reads 5720, physical reads 4, read-ahead reads 5728, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'CustomersBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Ainda que o número de reads seja menor, o tempo foi de 13 segundos, contra 7 do plano sem bushy plan, também podemos perceber que existe um sort warning no profiler, ou seja, a operação de sort foi escrita em disco, provavelmente esse foi o motivo da performance ser tão ruim, o que podemos tentar fazer é evitar esse SORT, como? Forçando o JOIN entre os resultados ser executado utilizando o algoritmo de HASH JOIN, vejamos a diferença: -- Gerar "cold cache" CHECKPOINT; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO ;WITH JoinEntre_CustomersBig_e_OrdersBig AS ( SELECT OrdersBig.OrderID, OrdersBig.Value, CustomersBig.ContactName, CustomersBig.CityID FROM CustomersBig INNER JOIN OrdersBig M V T e c h | 152 SQL Server: Além do Conceito Blog Post Collection ON OrdersBig.CustomerID = CustomersBig.CustomerID ), JoinEntre_ProductsBig_e_Order_DetailsBig AS ( SELECT Order_DetailsBig.OrderID, Order_DetailsBig.Quantity, ProductsBig.ProductName FROM ProductsBig INNER JOIN Order_DetailsBig ON Order_DetailsBig.ProductID = ProductsBig.ProductID ) SELECT JoinEntre_CustomersBig_e_OrdersBig.OrderID, JoinEntre_CustomersBig_e_OrdersBig.Value, JoinEntre_ProductsBig_e_Order_DetailsBig.Quantity, JoinEntre_CustomersBig_e_OrdersBig.ContactName, JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName FROM JoinEntre_CustomersBig_e_OrdersBig INNER HASH JOIN JoinEntre_ProductsBig_e_Order_DetailsBig ON JoinEntre_CustomersBig_e_OrdersBig.OrderID = JoinEntre_ProductsBig_e_Order_DetailsBig.OrderID WHERE JoinEntre_CustomersBig_e_OrdersBig.ContactName = 'Karl Jablonski 1E663869' AND JoinEntre_ProductsBig_e_Order_DetailsBig.ProductName = 'Ravioli Angelo D01AFCFC' OPTION (FORCE ORDER, MAXDOP 1) GO Vejamos a performance: STATISTICS IO: Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0 Table 'Order_DetailsBig'. Scan count 1, logical reads 9, physical reads 2, read-ahead reads 6 Table 'ProductsBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 M V T e c h | 153 SQL Server: Além do Conceito Blog Post Collection Table 'OrdersBig'. Scan count 1, logical reads 5720, physical reads 4, read-ahead reads 5728 Table 'CustomersBig'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0 Repare que ainda que tenhamos a presença de um Hash Warning indicando que parte da operação de hash utilizou tempdb (disco) ainda assim temos performance melhor que a consulta sem bushy join, neste caso o tempo foi de de 4 segundos. O que precisamos ter em mente é o seguinte, quanto menos linhas forem retornadas dos joins, melhor será a performance do bushy plan, se você por exemplo utilizar um filtro de cliente ou produto que não existe terá uma performance sensacional. CONCLUSÃO N OTA IMPORTANTE : A demonstração acima é meramente ilustrativa, eu não estou dizendo pra você sair utilizando FORCE ORCER ou qualquer outro hint em todas as consultas do seu ambiente, meu objetivo é te apresentar a funcionalidade e dizer para usar com consciência, se não entendeu, não use, o efeito do mal uso dessa técnica ou do uso de qualquer outro hint pode ser desastroso, portanto cuidado. Bom é isso pessoal, o mundo otimização de consultas é enorme e muitas vezes consistem no processo de tentativa e erro, porém conhecer bem as alternativas existentes e como o otimizador de consultas funciona, nos ajuda a minimizar este processo árduo de tentar otimizar um plano. Espero que você tenha chegado até aqui e gostado do artigo, trabalhei com conceitos importantes do otimizador de consultas e saiba que nem sempre o resultado real é o que foi estimado. That’s all folks. REFERÊNCIAS: ACM Paper: Left-deep vs. bushy trees: an analysis of strategy spaces and its implications for query optimization G. Graefe. The Cascades framework for query optimization. Data Engineering Bulletin, 18(3), 1995. Microsoft Research: Polynomial Heuristics for Query Optimization Itzik Ben-Gan: T-SQL Deep Dives: Create Efficient Queries Benjamin Nevarez: Optimizing Join Orders Wikipedia: http://en.wikipedia.org/wiki/Query_optimizer M V T e c h | 154 SQL Server: Além do Conceito Blog Post Collection Sulamita Dantas www.sulamitadantas.com.br Policy Based Management O PBM (Policy Based Management - Gerenciamento Baseado em Política) passou a ser utilizado a partir da versão do SQL Server 2008, permitindo uma padronização das instâncias, uma vez que nas versões anteriores, a mesma tinha que ser feita manualmente, ou seja, o BPM permite ao DBA ter o controle do seu ambiente, aplicando as melhores práticas de organização e segurança, tornando mais fácil o seu processo de manutenção. Quando o servidor possui poucas instâncias, tudo bem, dá para o DBA administrar manualmente, mas e quando são vários servidores e muitas instâncias em cada um deles? Já imaginou o trabalho que o DBA tem para ter o controle? Exemplo: se o DBA precisava criar uma rotina com as melhores práticas para saber quais bancos estavam com o AutoShrink e AutoClose desabilitados, ele tinha quer ir manualmente, e olhar banco por banco nas instâncias, ou criar scripts enormes para fazer tal verificação. Através do PBM é possível verificar de imediato quais bancos em uma instância estão com o AutoShrink e AutoClose desabilitados. De acordo com Mike Hotek1, O BPM possui alguns conceitos básicos: Facet - São o objeto básico sobre o qual os padrões são estabelecidos. Definem o tipo de objeto ou opção a ser verificada, como banco de dados por exemplo. Condition - São equivalentes a uma cláusula WHERE, que define os critérios que precisam ser verificados. Policy - É a união da Facet com a Condition On Change: Prevent - Cria Triggers DDL, para impedir uma alteração que viole a diretiva. On Change: Log Only - Verifica a diretiva automaticamente quando é feita uma alteração usando a infraestrutura de notificação de evento. On Schedule - Cria uma tarefa do SQL Server Agent para verificar a diretiva em um horário definido. On Demand - Avalia a diretiva quando executada diretamente por um usuário. 1 Hotek, Mike. Kit de treinamento MCTS(Exame 70-432): Microsoft SQL SERVER 2008: Implementação e manutenção/ Mike Hotek. M V T e c h | 155 SQL Server: Além do Conceito Blog Post Collection Após entender os conceitos acima, segue abaixo o exemplo: implementar uma política de melhores práticas para um banco ou vários bancos(AutoShrink e AutoClose desabilitados): - Abrir Management Studio - Ao Expandir a aba Management, clique em cima de Condition com o botão direito do mouse, selecione new condition: Nos campos abaixo: Name: coloque o nome da politica Facet: escolha uma das facetas que deseja usar para criar a política(nesse caso, será a Database). Expression: nesse campo crie a expressão de acordo com condição desejada. M V T e c h | 156 SQL Server: Além do Conceito Blog Post Collection Após clicar em ok, já pode verificar que a condição foi criada. Agora ó próximo passo é criar a policie: clique com o botão direito do mouse em cima de policie, selecione new policie M V T e c h | 157 SQL Server: Além do Conceito Blog Post Collection Nos campos abaixo: M V T e c h | 158 SQL Server: Além do Conceito Blog Post Collection Name: coloque o nome da policie Check Condition: clique na seta e ache a condição que foi criada. Against Targets: Selecione Every Database Evaluation Mode: On Demand Após clicar em ok, verifique a policie criada Verificando a política das melhores práticas: Clicar com o botão do mouse direito em cima da policie criada Selecionar Evaluate M V T e c h | 159 SQL Server: Além do Conceito Blog Post Collection Clique na opção view M V T e c h | 160 SQL Server: Além do Conceito Blog Post Collection Existem várias opções das facets, basta escolher qual deseja e criar! M V T e c h | 161 SQL Server: Além do Conceito Blog Post Collection Marcelo Fernandes marcelodba.wordpress.com Solucionando Problemas: Error Failed to open loopback connection ao executar SP_READERRORLOG INTRODUÇÃO Tenho um ambiente com SQL Server 2008 instalado em um Windows Server 2008 R2 Service Pack 1 em Cluster, ao executar ao procedure SP_READERRORLOG é exibida uma mensagem de erro Failed to open loopback connection. S INTOMA Ao executar a SP_READERRORLOG o seguinte erro ocorre: Msg 22004, Level 16, State 1, Line 0 Failed to open loopback connection. Please see event log for more information. Msg 22004, Level 16, State 1, Line 0 error log location not found C AUSA Ao executar o SP_READERRORLOG o SQL Server abre uma conexão com o próprio servidor (loopback) e neste momento o erro ocorria, para identificar o erro iniciei o ProcessMonitor que pode ser baixado no site da Microsoft, e ao executar o sp_readerrorlog juntamente com o ProcessMonitor notei o erro abaixo no ProcessMonitor. M V T e c h | 162 SQL Server: Além do Conceito Blog Post Collection Observando minha estrutura de cluster, o SQL Server está tentando abrir uma conexão com o nome do meu recurso de MSDTC. Sabemos que o SP_READERRORLOG faz uma conexão no loopback, mas por algum motivo recebi uma tentativa de conexão no nome do recurso de MSDTC (MSDTCP12) do meu cluster, ao observar as dependências do serviço do SQL observei que o serviço SQL dependia do nome MSDTCP12. S OLUÇÃO M V T e c h | 163 SQL Server: Além do Conceito Blog Post Collection Remova a dependência de qualquer recurso name que não seja o nome de sua instância SQL (no meu caso o nome do DTC) L EITURAS ADICIONAIS O Fabricio Catae tem um artigo com o mesmo erro, mas com origens distintas http://blogs.msdn.com/b/fcatae/archive/2010/03/03/problema-the-system-detected-apossible-attempt-to-compromise-security-parte-1.aspx M V T e c h | 164 SQL Server: Além do Conceito Blog Post Collection Error to install SQL Server 2008 on Windows 2012 Hello Friends… This week I faced an interesting error… My PFE friend Alex Rosa (blog) helped me to fix this problem and I’m sharing this problem / solution because it might help you. The environment and Goal A Windows 2012 R2 on cluster with 2 nodes and my goal was to setup a SQL Server 2008 in cluster. The problem Firstly, I must say that since Jul/14 SQL 2K8 is no longer supported, SQL2K8 is in Extended Support. When SQL Server 2008 was released there wasn’t Windows 2012, so SQL Server was made based on Windows 2k8, I’m not saying that SQL 2k8 is not supported on Windows 2012, SQL is supported on Windows 2012. but some functionality were made based on Win2K8. During the installation of SQL2K8 on Win12 on the first node I faced this error message: M V T e c h | 165 SQL Server: Além do Conceito Blog Post Collection I do have my Cluster on online status and working well and I ran the cluster validation successfully, but during the SQL setup I faced a message error saying that my setup couldn’t check my cluster service, bellow we have part of the detail of the Report Setup Validation: InstallFailoverClusterGlobalRules: SQL Server 2008 Setup configuration checks for rules group ‘InstallFailoverClusterGlobalRules’ SQLNOD E1 Cluster_IsOnline Verifies that the cluster service is online. M V T e c h | 166 Faile d The SQL Server failover cluster services is not online, or the cluster cannot be accessed from one of its SQL Server: Além do Conceito Blog Post Collection nodes. To continue, determine why the cluster is not online and rerun Setup. Do not rerun the rule because the rule cannot detect a cluster environme nt. SQLNOD E1 Cluster_SharedDiskF acet Checks whether the cluster on a compute r has at least one shared disk available . Faile d The cluster on this computer does not have a shared disk available. To continue, at least one shared disk must be available. SQLNOD E1 Cluster_VerifyForErr ors Checks if the cluster has been verified and if there are any errors or Faile d The cluster either has not been verified or there are errors or failures in the verification M V T e c h | 167 SQL Server: Além do Conceito Blog Post Collection failures reported in the verificati on report. report. Refer to KB953748 or SQL Server Books Online for more informatio n. I also tried running the setup from the command line using the SKIP_RULES: Setup /SkipRules=Cluster_VerifyForErrors /Action=InstallFailoverCluster And I got the same error… Looking at the detail of the first error, the message says that the SQL couldn’t verify the cluster service, the cluster was online but setup couldn’t access my cluster. I did some research on the web and I found this article: http://blogs.msdn.com/b/clustering/archive/2012/04/06/10291601.aspx The author (Rob-MSFT) gave me a clue: … These are deprecated features (Failover Cluster Command Interface (cluster.exe) and Failover Cluster Automation Server) in Windows Server 2012 but are made available, as there are still some applications that may need them, SQL Server being one of them. Installing it may be necessary for any legacy scripts you have built on the old Cluster.exe command line interface. … During the SQL Server 2008 installations the setup tries to check cluster service using a deprecated feature! Checking my cluster installations using the articles from Rob I have this: Get-WindowsFeature RSAT-Cluster* M V T e c h | 168 SQL Server: Além do Conceito Blog Post Collection These is the features installed by default when we install the Cluster Feature. The Solution We just need to enable the Failover Cluster Automation Server, to achieve this you just need to run the PowerShell command bellow. Install-WindowsFeature -Name RSAT-Clustering-AutomationServer After these steps we’ll have success on our setup: M V T e c h | 169 SQL Server: Além do Conceito Blog Post Collection PS: You need to run these steps on all Cluster nodes. Regards…. M V T e c h | 170 SQL Server: Além do Conceito Blog Post Collection Token Bloat - Cannot generate SSPI context Olá amigos, há um tempo atrás enfrente o famoso problema SSPI atípico e sempre adiava este post, bom finalmente tomei decidi escrever o artigo. P ROBLEMA Um usuário sempre conectou ao SQL Server sem problemas, mas um dia ao tentar conectar-se ao mesmo serviço de SQL ele recebeu a seguinte mensagem: Não houve nenhuma mudança por parte de infraestrutura e DBAs no servidor, o usuário simplesmente não consegue conectar mais, e o mais intrigante é que outros usuários conseguem conectar-se e alguns não. Bom, na grande maioria das vezes o erro SSPI Context é gerado por falta de SPN em uma tentativa de conexão via kerberos com o SQL Server e para resolver este problema basta criar o SPN. Listando os SPN atuais: No prompt de comando digite o seguinte comando M V T e c h | 171 SQL Server: Além do Conceito Blog Post Collection SETSPN –L <domínio\conta_de_serviço_do_SQL> Nota: Se ao executar o comando setspn –L você não receber o SPN para a sua instância de SQL Server, você deve criar o SPN e você está recebendo o erro de SSPI Context, possivelmente o seu problema será resolvido com a criação manual do SPN com o seguinte comando: SETSPN – A MSSQLSvc/fqdn <domínio>\<conta de serviço do SQL> SETSPN – A MSSQLSvc/fqdn:1433 <domínio>\<conta de serviço do SQL> Ex. SETSPN –A MSSLSvc/sqlproducao.contoso.com contoso\sqlServiceAcc Maiores informações no artigo: https://msdn.microsoft.com/pt-br/library/ms191153.aspx Como podemos observar no resultado do SETSPN –L no meu ambiente eu tenho os SPNs corretamente criados! O que justifica algumas conexões conseguirem conectar-se, pois o SPN está ok, e então por que algumas conexões recebem o SSPI? Para responder esta questão precisamos analisar o ticket do kerberos, executando a ferramenta tokensz você poderá evidenciar o problema de token bloat com a seguinte sintaxe tokensz.exe /compute_tokensize /user:<usuário_com_erro_sspi> M V T e c h | 172 SQL Server: Além do Conceito Blog Post Collection Como podemos notar na imagem acima, o tamanho máximo do Token é 12000 (12K) e o token do usuário contoso\usuarioSQL que estou tentando conectar-se ao SQL e estou recebendo o erro SSPI contexto ultrapassou o limite me 67 Bytes Um token basicamente contém os grupos e permissões de um usuário e é criado no momento do logon e este token é repassado aos outros serviços/servidores conforme o usuário necessita autenticar-se para consumir os serviços (para maiores detalhes sobre kerberos consulte o artigo https://msdn.microsoft.com/en-us/library/bb742516.aspx) Pois bem, se em um token temos a ACL (Access control List) vamos investigar os usuários criados: M V T e c h | 173 SQL Server: Além do Conceito Blog Post Collection Os dois usuários são membros do grupo SQLacesso o qual foi criado o login no SQL Server, mas o segundo usuário é membro de mais algumas centenas de grupos. Até o Windows 2008 R2 o tamanho máximo default de um token é de 12K a partir do Windows 2012 este valor foi alterado para 48K Dependendo do tamanho de seu ambiente este limite de 12K é facilmente alcançado com um usuário pertencendo a aproximadamente 150 grupos. Em uma empresa multinacional onde como boa prática são criados diversos grupos para controlar acessos a diversos compartilhamentos, servidores, aplicações etc. este limite é alcançado muito rapidamente. Qual o tamanho de cada grupo? Para calcular o tamanho do token utilizamos a seguinte formula: TokenSize = 1200 + 40d + 8s Onde: D = (grupos domínio local + grupos universais externos) S = (grupos globais + Universal) Existem diversos scripts que automatizam este cálculo, abaixo um bem simples que encontrei no artigo http://www.cluberti.com/blog/2014/05/26/getting-kerberos-token-size-with-powershell/ # Always credit where due - this was found via # http://jacob.ludriks.com/getting-kerberos-token-size-with-powershell/ M V T e c h | 174 SQL Server: Além do Conceito Blog Post Collection #Gets max token size #Run with .\get_tokensize.ps1 -Username "domain\username" #Reference: http://support.microsoft.com/kb/327825 #tokensize = 1200 + 40d + 8s Param( [Parameter(Mandatory=$True)] [String]$Username ) $domain = ($username.split("\"))[0] $user = ($username.split("\"))[1] Import-Module ActiveDirectory $rootdse = (Get-ADDomain $domain).distinguishedname $server = (Get-ADDomain $domain).pdcemulator $usergroups = Get-ADPrincipalGroupMembership distinguishedname,groupcategory,groupscope,name -server $server $user | select $domainlocal = [int]@($usergroups | where {$_.groupscope -eq "DomainLocal"}).count $global = [int]@($usergroups | where {$_.groupscope -eq "Global"}).count $universaloutside = [int]@($usergroups | where {$_.distinguishedname -notlike "*$rootdse" -and $_.groupscope -eq "Universal"}).count $universalinside = [int]@($usergroups | where {$_.distinguishedname -like "*$rootdse" -and $_.groupscope -eq "Universal"}).count $tokensize = 1200 + (40 * ($domainlocal + $universaloutside)) + (8 * ($global + $universalinside)) Write-Host " Domain local groups: $domainlocal Global groups: $global Universal groups outside the domain: $universaloutside Universal groups inside the domain: $universalinside Kerberos token size: $tokensize" M V T e c h | 175 SQL Server: Além do Conceito Blog Post Collection Outros scripts úteis http://www.jhouseconsulting.com/2013/12/20/script-to-create-a-kerberos-token-size-report-1041 https://gallery.technet.microsoft.com/scriptcenter/Check-for-MaxTokenSize-520e51e5 C OMO R ESOLVER Você tem duas maneiras de resolver o problema, aumentando o default do token size ou excluindo grupos desnecessários. Para aumentar o token size, você pode seguir as etapas do KB http://support.microsoft.com/kb/938118 E M CADA ESTAÇÃO : Inicie Regedt32.exe Localize a chave (HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters) No menu Edit clique em NEW / DWORD e utilize os parâmetros abaixo: Nome: MaxTokenSize tipo: REG_DWORD Base: Decimal Valor: 48000 Feche o Editor de Registro Se executarmos novamente a ferramenta Tokensz teremos o seguinte resultado: M V T e c h | 176 SQL Server: Além do Conceito Blog Post Collection LEITURAS ADICIONAIS http://support.microsoft.com/kb/938118 http://blogs.technet.com/b/shanecothran/archive/2010/07/16/maxtokensize-and-kerberos-tokenbloat.aspx http://support.microsoft.com/kb/327825/en-us http://blogs.technet.com/b/askds/archive/2012/07/27/kerberos-errors-in-network-captures.aspx http://blogs.technet.com/b/askds/archive/2007/11/02/what-s-in-a-token.aspx http://support.microsoft.com/kb/327825/en-us http://blogs.technet.com/b/askds/archive/2012/09/12/maxtokensize-and-windows-8-and-windowsserver-2012.aspx M V T e c h | 177 SQL Server: Além do Conceito Blog Post Collection Cibelle Castro cibellecastro.wordpress.com Auditoria Descobrindo Auditoria no SQL Server 2008 Abordaremos neste artigo a auditoria em banco de dados, no entanto, antes de falarmos sobre isso, pense no que a palavra auditoria quer dizer para você. Onde você ouviu falar a primeira vez nessa palavra? Mas porque todas essas perguntas? O objetivo delas é demonstrar que independente da área que a auditoria seja implementada, todas desejam um mecanismo para ajudar a descobrir algo sobre alguém, alguma coisa, alguma ação, nos mostrar que tentaram entrar no sistema, enfim dar segurança aos nossos dados. Qual DBA nunca se deparou com a seguinte situação: “Ahhhhhh alguém tirou as minhas permissões!” ou “Quero saber quem alterou a stored procedure que eu fiz, semana passada ela estava funcionando”, ou qualquer relação que necessitamos rastrear as alterações que foram feitas nos dados. Quem fez, quando fez e o que foi modificado? Dependendo da empresa, será primordial ter uma auditoria implementada, seja ela exigida pelo ramo do negócio ou por determinação da lei. Antes do SQL Server 2008, era necessário utilizar diversos recursos para fazer todo o conjunto de auditoria para uma instância. Usávamos as triggers DDL como o próprio nome diz faziam a auditoria de alterações DDL, as triggers DML faziam a auditoria dos dados modificados em tabelas ou views, tinha a opção de usar o SQL Trace fazia a auditoria de instruções SELECT ou ainda algumas ferramentas de terceiros. O SQL Server 2008 possui uma ferramenta excelente, o SQL Server Audit combina todos os recursos de auditoria. P OR QUE UTILIZAR AUDI TORIA ? Você poderia estar se perguntando: quais as vantagens de implementar auditoria do SQL Server no meu ambiente? SQL Server Audit possui várias características e benefícios, dentre elas: Auditoria em nível de instância e banco de dados; Auditoria de atividades; Capacidade de capturar e exibir os resultados da auditoria; Alta granularidade; Leve e rápido; Facilidade de configurar e administrar; Mais complexo e mais fácil que utilizar triggers; M V T e c h | 178 SQL Server: Além do Conceito Blog Post Collection Facilidades através do SSMS; P ODE SER FEITO ATRAVÉS DE S CRIPTS . N OTA 01: O SQL Server Audit utiliza Extended Events Engine para capturar os dados da auditoria. Isso resulta em um rápido desempenho e sobrecarga mínima em comparação ao uso de SQL Trace para capturar esse tipo de atividade. C OMO O SQL S ERVER A UDIT TRABALHA ? Nesta seção, vamos ver uma visão geral de como funciona o SQL Server Audit. O fluxograma mostrado na Figura 1 deve fornecer uma visão ampla do que está envolvido na criação de auditoria. Figura 01. Fluxograma que mostra como criar uma nova auditoria de servidor SQL A auditoria do SQL Server permite que você crie várias auditorias diferentes, atendendo a maior parte todas das atividades que ocorre dentro do SQL Server. Existem quatro principais objetos para se configurar a auditoria, Server Audit Object, Target, Server Audit Specification e o Database Audit Specification, vamos detalhar um pouco mais sobre cada item: O primeiro passo ao criar uma nova auditoria em uma instância do SQL Server 2008 é criar um SQL Server Audit Object, que é responsável por coletar e agrupar as ações que serão monitoradas. M V T e c h | 179 SQL Server: Além do Conceito Blog Post Collection Quando você cria um SQL Server Audit Object, deve-se atribuir um nome, selecionar as opções de configuração, e dizer qual é o TARGET. O TARGET é o local onde os dados de auditoria serão armazenados que pode ser um arquivo no disco (audit file), o log de aplicações do Windows (Application EVENT LOG) ou no log de segurança do Windows (Security EVENT LOG). Se a forma de armazenamento escolhida for “audit file”, você poderá escolher a pasta onde esses arquivos serão gerados e poderá especificar o tamanho máximo de um arquivo. Além disso, é possível alocar previamente espaço em disco para o log de auditoria, em vez de fazer o arquivo crescer à medida que as linhas de auditoria são adicionadas. Quando o Application ou o Security Log são especificados, as únicas opções disponíveis para configuração são: Queue Delay: quantidade de tempo em milissegundos que os eventos são armazenados antes de serem armazenados. Para permitir que a entrega de eventos seja síncrona, você deve preencher esse campo com “0” (QUEUE_DELAY = 0). O valor default é “1000”, o que equivale a 1 segundo. Se especificar um tempo de atraso, os registros de auditoria poderão ser acumulados, mas mesmo assim deverão ser gravados dentro do intervalo especificado; Shutdown on Failure: A ação ON_FAILURE controla como a instância se comporta se os registros de auditoria não podem ser gravados. A opção default é CONTINUE, a qual permite que a instância continue a execução e processe as transações. Caso você altere o valor para SHUTDOWN, a instância será encerrada se os eventos de auditoria não puderem ser escritos no target. Sintaxe Server Audit: CREATE SERVER AUDIT audit_name { TO { [ FILE (<file_options> [ , ...n ]) ] | APPLICATION_LOG | SECURITY_LOG } [ WITH ( <audit_options> [ , ...n ] ) ] } [ ; ] <file_options>::= { FILEPATH = 'os_file_path' [ , MAXSIZE = { max_size { MB | GB | TB } | UNLIMITED } ] [ , MAX_ROLLOVER_FILES = { integer | UNLIMITED } ] [ , RESERVE_DISK_SPACE = { ON | OFF } ] } <audit_options>::= { [ QUEUE_DELAY = integer ] [ , ON_FAILURE = { CONTINUE | SHUTDOWN } ] M V T e c h | 180 SQL Server: Além do Conceito Blog Post Collection [ , AUDIT_GUID = uniqueidentifier ] } Se você prestar atenção na sintaxe, perceberá que pode ser facilmente configurado. N OTA 02: Não é possível escrever no log de segurança no Windows XP; Um objeto de auditoria sempre inicia desabilitado; O log de segurança pode ser integrado com o ACS (AUDIT COLLECTION SERVICES) do System Center Operations Manager 2007; Qualquer usuário autenticado pode ler/escrever no log de aplicações do Windows. Este log requer menos permissões e é menos seguro que o log de segurança do Windows. O segundo passo é criar o que é chamado de Audit Specification. A auditoria do SQL Server oferece dois tipos diferentes de especificações de auditoria: SERVER AUDIT SPECIFICATIONS; DATABASE AUDIT SPECIFICATIONS; Server e Database Audit Specification são criados de forma diferente. Vamos conhecer um pouco mais o conceito de cada um desses tipos. SERVER AUDIT SPECIFICATIONS Define os grupos de ações (action groups) que ocorrem no nível de instância do SQL Server e os agrupa em “audit action groups”. Por exemplo, podem ser usados quando você deseja auditar uma atividade, tais como login, logout, alterações de senhas, quando um comando de backup ou restore é disparada dentre outas coisas . Existe um relacionamento um-para-um entre o Server Audit Specification Object e o Server Audit Object. A regra é simples um SQL Server Audit Object só pode ser associado com um Audit Specification porque ambos são criados no escopo da instância do SQL Server. As ações auditadas são enviadas para o SQL Server Audit que grava essas ações no TARGET. Na tabela 01 estão descritos os audit actions groups. Action Group Name M V T e c h | 181 SQL Server: Além do Conceito Blog Post Collection APPLICATION_ROLE_CHANGE_PASSWORD_GROUP AUDIT_CHANGE_GROUP BACKUP_RESTORE_GROUP BROKER_LOGIN_GROUP DATABASE_CHANGE_GROUP DATABASE_MIRRORING_LOGIN_GROUP DATABASE_OBJECT_ACCESS_GROUP DATABASE_OBJECT_CHANGE_GROUP DATABASE_OBJECT_OWNERSHIP_CHANGE_GROUP DATABASE_OBJECT_PERMISSION_CHANGE_GROUP DATABASE_OPERATION_GROUP DATABASE_OWNERSHIP_CHANGE_GROUP DATABASE_PERMISSION_CHANGE_GROUP DATABASE_PRINCIPAL_CHANGE_GROUP DATABASE_PRINCIPAL_IMPERSONATION_GROUP DATABASE_ROLE_MEMBER_CHANGE_GROUP DBCC_GROUP FAILED_LOGIN_GROUP FULLTEXT_GROUP LOGIN_CHANGE_PASSWORD_GROUP LOGOUT_GROUP SCHEMA_OBJECT_ACCESS_GROUP SCHEMA_OBJECT_CHANGE_GROUP SCHEMA_OBJECT_OWNERSHIP_CHANGE_GROUP SCHEMA_OBJECT_PERMISSION_CHANGE_GROUP SERVER_OBJECT_CHANGE_GROUP SERVER_OBJECT_OWNERSHIP_CHANGE_GROUP M V T e c h | 182 SQL Server: Além do Conceito Blog Post Collection SERVER_OBJECT_PERMISSION_CHANGE_GROUP SERVER_OPERATION_GROUP SERVER_PERMISSION_CHANGE_GROUP SERVER_PRINCIPAL_CHANGE_GROUP SERVER_PRINCIPAL_IMPERSONATION_GROUP SERVER_ROLE_MEMBER_CHANGE_GROUP SERVER_STATE_CHANGE_GROUP SUCCESSFUL_LOGIN_GROUP TRACE_CHANGE_GROUP Tabela 01 – Audit Action Groups. Fonte: http://technet.microsoft.com/en-us/library/cc280663.aspx Podemos obter o resultado da Tabela 01 fazendo uma consulta na DMV sys.dm_audit_actions. SELECT --Action_in_log -> Indica se uma ação pode ser gravada em um log de auditoria. Os valores são os seguintes: 1 = Sim e 0 = Não Action_in_log, --Name -> Nome da ação de auditoria ou do grupo de ações de auditoria. Não pode ser nulo. Name FROM Sys.dm_audit_actions WHERE -- Class_desc -> O nome da classe do objeto ao qual a ação de auditoria aplica-se Class_desc ='SERVER' -- Configuration_level ->Indica que a ação ou o grupo de ações especificado nessa linha são configuráveis no nível do Grupo ou da Ação AND Configuration_level ='Group' ORDER BY Name Ao criar qualquer tipo de Audit Specification (Nota 02), você primeiro atribuir-lhe um nome e associa o Audit Specification com o SQL Server Audit Object criado na primeira etapa. O último passo para criação de uma especificação de auditoria de servidor é atribuir-lhe um Audit Action type que nada mais é do que uma atividade pré-definida que acontece dentro do SQL Server e podem ser auditadas. M V T e c h | 183 SQL Server: Além do Conceito Blog Post Collection N OTA 03: Sintaxe para criar um Server Audit Specification por T-SQL: CREATE SERVER AUDIT SPECIFICATION audit_specification_name FOR SERVER AUDIT audit_name { { ADD ( { audit_action_group_name } ) } [, ...n] [ WITH ( STATE = { ON | OFF } ) ] } [ ; ] DATABASE AUDIT SPECIFICATIONS Usado quando você deseja auditar uma atividade dentro de um banco de dados, como quem está selecionando dados de uma tabela particular. A regra é a cada Database Audit Specification pode ser associado a apenas um Server Audit Object. Entretanto um Server Audit Object pode ser associado a apenas um Database Audit Specification por banco de dados. Ou seja, você pode criar múltiplos Database Audit Speficications por banco de dados desde que cada um use um Server Audit Object separado. Veja Figura 02. M V T e c h | 184 SQL Server: Além do Conceito Blog Post Collection Figura 02. Descrição geral de auditoria. No nível de instância, você pode especificar um ou mais Audit Action Group (para Database Audit Specification você pode especificar ações de auditoria individual e filtros também). Na tabela 02 estão descritos as ações ou grupos de ação que podem ser configurados. Action Name Action Group Name DELETE APPLICATION_ROLE_CHANGE_PASSWORD_GROUP EXECUTE AUDIT_CHANGE_GROUP INSERT BACKUP_RESTORE_GROUP RECEIVE DATABASE_CHANGE_GROUP REFERENCES DATABASE_OBJECT_ACCESS_GROUP SELECT DATABASE_OBJECT_CHANGE_GROUP UPDATE DATABASE_OBJECT_OWNERSHIP_CHANGE_GROUP DATABASE_OBJECT_PERMISSION_CHANGE_GROUP DATABASE_OPERATION_GROUP DATABASE_OWNERSHIP_CHANGE_GROUP DATABASE_PERMISSION_CHANGE_GROUP DATABASE_PRINCIPAL_CHANGE_GROUP DATABASE_PRINCIPAL_IMPERSONATION_GROUP DATABASE_ROLE_MEMBER_CHANGE_GROUP DBCC_GROUP SCHEMA_OBJECT_ACCESS_GROUP SCHEMA_OBJECT_CHANGE_GROUP SCHEMA_OBJECT_OWNERSHIP_CHANGE_GROUP SCHEMA_OBJECT_PERMISSION_CHANGE_GROUP Tabela 02. Fonte: http://technet.microsoft.com/en-us/library/cc280663.aspx M V T e c h | 185 SQL Server: Além do Conceito Blog Post Collection Neste objeto podemos coletar dados como DELETE, INSERT, SELECT, UPDATE, EXECUTE, DBCC_GROUP etc. Para visualizarmos todos os objetos descritos na Tabela 02, basta fazermos uma pesquisa na DMV sys.dm_audit_actions. SELECT --Action_in_log -> Indica se uma ação pode ser gravada em um log de auditoria. Os valores são os seguintes: 1 = Sim e 0 = Não Action_in_log, --Name -> Nome da ação de auditoria ou do grupo de ações de auditoria. Não pode ser nulo. Name FROM sys.dm_audit_actions WHERE -- Class_desc -> O nome da classe do objeto ao qual a ação de auditoria aplica-se class_desc='DATABASE' -- Configuration_level ->Indica que a ação ou o grupo de ações especificado nessa linha são configuráveis no nível do Grupo ou da Ação AND configuration_level IN ('Action','Group') ORDER BY name Ao criar uma especificação de auditoria de banco de dados, você atribui um nome, então associa ao Audit Specification com o SQL Server Audit Object e especifica o Audit Action Type como foi feito com o Server Audit Specification. No entanto, além disso, deve-se especificar o Object Class (database, object ou schema), o nome do objeto auditado e o security principal (ou seja, quem nós vamos auditar). Uma vez que o Audit Specification for concluído, você deve habilitar o SQL Server Audit Object e o Audit Specification. Apartir daí os eventos de auditoria começarão a ser coletados para o target designado. N OTA 03: Sintaxe para criar um Database Audit Specification por linha de comando: CREATE DATABASE AUDIT SPECIFICATION audit_specification_name { FOR SERVER AUDIT audit_name [ { ADD ( { <audit_action_specification> | audit_action_group_name } ) M V T e c h | 186 SQL Server: Além do Conceito Blog Post Collection } [, ...n] ] [ WITH ( STATE = { ON | OFF } ) ] } [ ; ] <audit_action_specification>::= { action [ ,...n ]ON [ class :: ] securable BY principal [ ,...n ] } P ASSA A P ASSO DE COMO CRIAR U MA A UDITORIA . Nesse exemplo vamos configurar os três targets disponíveis para configurar o Server Audit Objects. Iremos demostrar como fazer isso logo abaixo: a) O primeiro target que criaremos será Windows Application Event Log. Abra o Management Studio vá em: Security/ Audits/New Audit. Veja Figura 03. M V T e c h | 187 SQL Server: Além do Conceito Blog Post Collection Figura 03. Criação auditoria A primeira coisa que você precisa fazer é atribuir o nome ou usar o nome que é gerado automaticamente. Preencha a opção Audit Name(aconselho a colocar um nome intuitivo para que possa identificar do que se trata), no nosso caso estou colocando o nome do target mais a forma que ele esta sendo criado. Ou seja, ApplicationLog + SSMS = ApplicationLog SSMS . Veja Figura 04. M V T e c h | 188 SQL Server: Além do Conceito Blog Post Collection Figura 04. Configuração parâmetros de auditoria. Nesse exemplo estamos configurando o Queue delay para 3000 milissegundos. Na Tabela 03 descreve todos os parâmetros existentes na Figura 04. Parâmetros Descrição Queue Delay E informado o valor que indica de quanto em quanto tempo será descarregado antes das ações de auditoria serem processadas. M V T e c h | 189 SQL Server: Além do Conceito Blog Post Collection Se essa opção for selecionada e exista uma tentativa de escrever no Shut down Server on arquivo de auditoria e ocorrer uma falha ele vai parar o serviço, audit log failure evitando assim falhas na auditoria. Você pode salvar eventos capturados a qualquer um dos seguintes destinos Audit Destination *File *Application_Log *Security_Log File Path Se o Audit Destination escolhido foi à opção FILE, então você precisa fornecer o caminho onde os arquivos de auditoria serão salvos. Maximum Rollover E informado o numero de arquivos que vão ser gerados. Maximum File Size Especifica o tamanho máximo de espaço em disco reservado para cada arquivo gerado para auditoria. Você pode escolher o botão que especifica a capacidade em MB, GB, TB ou a opção Unlimited(tome bastante cuidado ao escolher essa alternativa). Reserve Disk Space Ativando essa opção você ira reservar todo espaço em disco rígido M V T e c h | 190 SQL Server: Além do Conceito Blog Post Collection Na opção Audit Destination selecione “Application Log”. Ao fazer isso os outros parâmetros ficaram indisponíveis. Clique em OK. Veja Figura 05. Figura 05. Escolha do Audit destination. Por default o Server Audit Object é criado desabilitado. Para habilita-lo basta clicar com o botão direito do mouse em ApplicationLogSSMS e selecionar a opção “Enable Audit”. Veja Figura 06. M V T e c h | 191 SQL Server: Além do Conceito Blog Post Collection Figura 06. Habilitar Server Audit Object Para criar o mesmo Server Audit demostrado acima usando T-SQL basta executar os comandos abaixo: CREATE SERVER AUDIT [TargetApplicationLogTSQL] TO APPLICATION_LOG WITH ( QUEUE_DELAY = 3000, ON_FAILURE = CONTINUE ) GO O parâmetro ON_FAILURE só pode ser configurado para aqueles logins que possuem permissão SHUTDOWN. Se o usuário que esta tentando executar esse comando não tiver essa permissão, a função irá falhar com uma mensagem MSG_NO_SHUTDOWN_PERMISSION. O segundo objeto que vamos configurar é para o Target FILE. Existem algumas opções adicionais que pode ser especificada. Incluindo qual a pasta que os arquivos de auditoria serão gerados, o número máximo de rollover files(Esse parâmetro é avaliado sempre que a auditoria é reiniciada ou quando um novo arquivo é necessário porque o MAXSIZE foi atingido. Se o número de arquivos excede o MAX_ROLLOVER_FILES o arquivos mais antigo é deletado), o tamanho máximo de cada arquivo e se é para reservar espaço em disco para o audit file(arquivo de auditoria). M V T e c h | 192 SQL Server: Além do Conceito Blog Post Collection F AREMOS ESSAS CONFIGU RAÇÕES DO S ERVER A UDIT ATRAVÉS DE TSQL E O M ANAGEMENT S TUDIO . Faça os passos descritos no item “1a”. Vamos atribui um nome para opção “Audit name”. No nosso caso o nome será: TargetFileSSMS. Veja Figura 07. Figura 07. Atribuição do Audit Name . Por causa do aumento da latência, devido à rede pode ser necessário aumentar o parâmetro QUEUE_DELAY para evitar afetar a instância. Colocaremos essa opção como 2000 milissegundos. Próximo passo será configurar o Audit Destination. Selecione a opção FILE. No parâmetro “File path” devemos dizer o nome da pasta onde serão armazenados os arquivos da auditoria. Neste exemplo estamos especificando a pasta de destino para C: \ Auditoria \. Em MAX_ROLLOVER_FILES digite 3. Pois será o numero máximo de arquivos gerados. Desabilite o check na opção “Unlimited” do parâmetro “Maximum file size”. Preencha esse campo com número 3 e deixe selecionado o tamanho MB (megabyte). Por fim, habite “Reserve disk space”. Veja na Figura 08 como ficaram todas as configurações. M V T e c h | 193 SQL Server: Além do Conceito Blog Post Collection Clique no botão OK. Pronto! O Server Audit foi criado com sucesso. Você estar se perguntando: Como posso criar o mesmo objeto através de comandos TSQL? Veja logo abaixo o script: USE master GO CREATE SERVER AUDIT TargetFileTSQL TO FILE ( M V T e c h | 194 SQL Server: Além do Conceito Blog Post Collection FILEPATH = N'C:\Auditoria', /*MAXSIZE = Especifica o tamanho máximo para o qual o arquivo de auditoria pode crescer*/ MAXSIZE = 3MB, /*MAX_ROLLOVER_FILES = Número máximo de arquivos que pode ser criados. O valor padrão é UNLIMITED. Lembrando que esse valor deve ser um número inteiro. Portanto o valor UNLIMITED = 0.*/ MAX_ROLLOVER_FILES = 3, /*RESERVE_DISK_SPACE = Esta opção de pré-aloca o arquivo no disco para o valor definifo no MAXSIZE. Aplica-se somente se MAXSIZE não é igual a UNLIMITED. O valor padrão é OFF*/ RESERVE_DISK_SPACE = ON ) WITH ( QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE ) Para visualizarmos os objetos criados (Veja Figura 09) basta utilizar o seguinte consulta: /*OBJETOS DE AUDITORIA CRIADOS*/ SELECT * FROM SYS.server_audits Figura 09. Resultado da consulta em sys.server_audits. Observe que na coluna type_desc descreve o tipo do target de cada Server Audit. Por fim o terceiro e último Target Windows Security Event Log. Antes de começamos a demonstrar como faremos a criação desse objeto, será necessário efetuarmos algumas configurações no Windows a fim de permitir que o SQL Server possa gravar eventos no Security Event Log. O servidor utilizado nessa demonstração é o Windows Server 2008). Primeiro clicamos no botão Iniciar \Executar\secpol.msc. Veja Figura 10. M V T e c h | 195 SQL Server: Além do Conceito Blog Post Collection Figura 10. Clique em Local Polices\ Audit Policy. Com o botão direito do mouse selecione Audit object access\ Properties. Marque as opções: Success e Failure. Estamos permitindo o acesso ao objeto de auditoria em casos de sucesso e falha. Veja Figura 11. Figura 11. Propriedades de acesso ao objeto de auditoria Precisamos atribuir direito de gerar Security Audits para a conta de serviço do SQL Server. Caso você não lembre ou não saiba qual usuário esta inicializando o SQL Server basta ir em Iniciar \Microsoft SQL Server 2008 R2 \ Configuration Tools \ SQL Server Configuration Maganer. Selecione o serviço com o botão direito e clique em Propriedades. Na aba Logon verifique a conta que está configurada o MSSQLSERVER. Veja Figura 12. M V T e c h | 196 SQL Server: Além do Conceito Blog Post Collection Figura 12. Parando o Serviço do SQL Server atraves do Configuration Manager. Depois de descoberto o usuário vamos finalmente atribuir a permissão para ele. Selecione User Rights Assignment \ Generate security audits. Clique no botão Add User or Group e adicione o usuário configurado na conta de serviço do SQL Server. Veja Figura 13. M V T e c h | 197 SQL Server: Além do Conceito Blog Post Collection Figura 13. Adicionando usuário da conta de serviço do SQL. Uma vez que estas duas alterações foram feitas, reinicie o serviço do SQL Server e então você vai ser capaz de criar um Server Audit no Windows Security Log. Observe que as opções definidas aqui podem muito bem serem efetuadas via Group Policy direto no servidor de domínio. Esse tipo de configuração deve ser discutido com os responsáveis pelo gerenciamento das Politicas de Segurança do Servidor e assim garantir que os ajustes necessários sejam colocados em vigor para que o SQL Server seja capaz de gravar eventos no Security Log. Para criar o Server Audit faça os passos descritos no item “1a”. Atribua um nome no campo “Audit Name”. O nome que adotaremos será TargetSecurityLogSSMS. Por default a opção “Queue delay in milliseconds” é preenchida com o valor 1000. Vamos alterar esse valor para 2000. Na opção “Audit destination” selecione Security Log. Perceba que as outras opções de configuração são desabilitadas assim que escolhemos essa opção. Veja Figura 14. M V T e c h | 198 SQL Server: Além do Conceito Blog Post Collection Figura 14. Configuração Audit destination. Caso tenha interesse em criar esse mesmo Server Audit através de comandos TSQL faça conforme script abaixo: CREATE SERVER AUDIT TargetSecurityLogTSQL TO SECURITY_LOG WITH ( QUEUE_DELAY = 2000, ON_FAILURE = CONTINUE ) GO M V T e c h | 199 SQL Server: Além do Conceito Blog Post Collection Como vimos nos exemplos acima, é extremamente simples criar Server Audit Objects no SQL Server 2008 usando TSQL ou SSMS. C RIANDO UM S ERVER OU S ERVER A UDIT S PECIFICATION . Agora que criamos o nosso Server Audit Objects precisamos adicionar especificação de auditoria correspondente. Se quisermos fazer uma auditoria no nível de instância, teremos que criar um Server Audit Specification. Vamos auditar toda vez que for gerado um backup ou restore no servidor. O nome do Action Group utilizado nesse exemplo será BACKUP_RESTORE_GROUP. Vamos criar o Server Audit Specification. Abra o SSMS vá em Security \Server Audit Specification \New Server Audit Specification.. Veja Figura 15. Figura 15. Criação do Server Audit Specification. Preencha o campo “Name”, nesse exemplo coloquei o nome da especificação de auditoria + action group = ServerAuditSpecificationBackupRestore. . Estou fazendo isso para facilitar o entendimento de que esta administrando o servidor de banco de dados, ou seja, nós mesmos. Na opção “Audit” devemos preencher com um dos Server Audit Objects criado anteriormente. Nesse caso vou querer armazenar os dados auditados no Application Log. Selecione a opção “TargetApplicationLogTSQL”. Veja Figura 16. M V T e c h | 200 SQL Server: Além do Conceito Blog Post Collection Figura 16. No campo Action \Audit Action Type, selecione BACKUP_RESTORE_GROUP. Ao fazer isso as outras opções de configuração seram desabilitadas. Clique no botão OK. Veja Figura 17. M V T e c h | 201 SQL Server: Além do Conceito Blog Post Collection Agora vamos habilitar o Server Audit Specification criado, para iniciarmos a coleta dos dados. Podemos fazer de duas maneiras, clicando com o botão direito em cima do objeto adicionado e selecionando a opção “Enable Server Audit Specification”, ou via TSQL. Veja Figura 18. M V T e c h | 202 SQL Server: Além do Conceito Blog Post Collection Figura 18. Se fosse através de consulta o script ficaria dessa maneira: ALTER SERVER AUDIT SPECIFICATION [ServerAuditSpecificationBackupRestore] WITH (STATE = ON) GO Os scripts da Listagem 01 cria um banco de dados, uma tabela, faz a inserção dos dados e por fim faz o backup e um restore para vermos se os dados realmente estão sendo auditados. M V T e c h | 203 SQL Server: Além do Conceito Blog Post Collection --CRIAR BANCO DE DADOS AUDITORIA IF (SELECT DB_ID ('AUDITORIA')) IS NULL BEGIN CREATE DATABASE AUDITORIA END GO --CRIAR TABELA CREATE TABLE TABServerSpecification (ID Int Identity(1,1) PRIMARY KEY, Nome VarChar(250)DEFAULT NewID()) INSERT INTO TABServerSpecification DEFAULT VALUES GO 10000 --FAZER BACKUP DO BANCO AUDITORIA BACKUP DATABASE Auditoria TO DISK = 'C:\Auditoria\Auditoria.bak' WITH FORMAT; GO -- DROP NO BANCO AUDITORIA DROP DATABASE AUDITORIA --RETORE BANCO DE DADOS AUDITORIA RESTORE DATABASE AUDITORIA FROM DISK = 'C:\Auditoria\Auditoria.bak' WITH RECOVERY GO Vamos verificar se o que acabamos de fazer foi realmente auditado, para isso selecione a guia Management \SQL Server Logs \ View SQL Server Log. Veja Figura 19. M V T e c h | 204 SQL Server: Além do Conceito Blog Post Collection Figura 19. Visualização do Log Selecione a seguinte opção: Windows NT \ Application . Veja Figura 20. M V T e c h | 205 SQL Server: Além do Conceito Blog Post Collection Figura 20. Dados auditados Verifique que todas as linhas que possuem uma chave foram os dados auditados, no nosso caso o backup e o restore que fizemos. C RIANDO UM S ERVER OU D ATABASE A UDIT S PECIFICATION . Nos próximo exemplo vamos criar um Database Audit Specification. O objetivo dessa auditoria será auditar a utilização das clausulas SELECT, INSERT, UPDATE e DELETE em duas tabelas de um único banco de dados. Você precisará do AdventureWorks instalado, para isso baixa baixar no site do Codeplex (http://msftdbprodsamples.codeplex.com/releases/view/55926). A primeira tarefa é criarmos um Server Audit, como nós já criamos na etapa 2b. Utilizaremos mesmo quando for solicitado. Para criar um Database Audit Specification você deve escolher o banco de dados que deseja fazer a auditoria. No nosso caso será o AdventureWorks. Clique com o botão direito em “Database Audit Specification” e selecione “New Audit Specification”, como mostrado na Figura 21. M V T e c h | 206 SQL Server: Além do Conceito Blog Post Collection Figura 21. Criar Novo Database Audit Specification. Na janela “Create Database Audit Specification” você pode aceitar o nome sugerido ou caso queira pode digitar seu próprio nome. Adotaremos o seguinte: Em seguida selecione a partir da caixa suspensa o Server Audit Object que armazenaremos os dados da auditoria. Dessa vez vamos armazenar os dados da auditoria em um arquivo, utilizaremos o Server Audit Object criado anteriormente. Selecione o Target TargetFileSSMS. Veja Figura 22. M V T e c h | 207 SQL Server: Além do Conceito Blog Post Collection Figura 22. Na seção “Audit Action Types”, você deve especificar o tipo de ação de auditoria que deseja capturar. No primeiro combo selecione a opção SELECT, com o objetivo de gravar toda atividade do comando SELECT para a tabela Veja Figura 23. M V T e c h | 208 SQL Server: Além do Conceito Blog Post Collection Figura 23. Agora devemos escolher “Object Class”. Vamos auditar mais de uma tabela de um banco especifico então selecione a segunda opção dessa coluna, ou seja, OBJECT. Devemos selecionar qual o OBJECT será auditado, para isto clique no botão “…” da coluna Object Name. Veja Figura 24. M V T e c h | 209 SQL Server: Além do Conceito Blog Post Collection Figura 24. Na janela “Select Objects” clique no botão “Browse…” Escolha as tabelas que serão monitoradas do banco AdventureWorks. Selecione as seguintes tabelas: HumanResources.Employee, Person.Contact, Production.Location e Production.UnitMeasure. Clique no botão OK (Observe que temos a opção de escolher mais de um database). A próxima etapa será escolher o “Principal Name”, ou seja, qual o usuário que queremos auditar. Nessa opção podemos selecionar Users e Roles. Para fazer isso, clique no botão “...” da coluna “Principal Name” e na janela “Select Objects” clique no botão “Browser..”. Agora você pode ver quais “Principals” pode escolher, nesse caso nos vamos escolher “ public” , pois o objetivo dessa auditoria é identificar qualquer pessoas que execute a cláusula SELECT na tabela xx , como mostrado na figura 25. M V T e c h | 210 SQL Server: Além do Conceito Blog Post Collection Figura 25. Concluímos o nosso primeiro filtro, vamos repetir as operações descritas acima para os comandos INSERT, UPDATE e DELETE. Veja Figura 26. Clique em OK para concluirmos a criação do Database Audit Specification. Assim como Server Audit Specification a especificação de banco de dados é criado desabilitado, se você observe vera que ele tem uma seta vermelha indicando que esta desativada, para habilita-la clique sobre o mesmo como botão direito e escolha a opção “Enable Database Audit Specification”. Agora vamos selecionar excluir, inserir e atualizar alguns registros das tabelas que estamos auditando para ver se tudo aquilo que configuramos esta funcionando conforme o esperado. Execute os scripts da Listagem 02. --AUDITANDO COMANDO SELECT USE AdventureWorks; Select P.FirstName + ' ' + C.LastName AS 'Nome’, M V T e c h | 211 SQL Server: Além do Conceito Blog Post Collection E.VacationHours AS 'Férias (horas)', E.SickLeaveHours AS 'Afastamento por motivo de doença (horas)', E.LoginID AS 'Login' FROM HumanResources.Employee E LEFT JOIN Person.Contact C ON E.ContactID = C.ContactID ORDER BY [Nome Completo]; --AUDITANDO COMANDO SELECT select * from Production.Location --AUDITANDO COMANDO UPDATE Update Person.Contact Set FirstName = 'Cibelle', emailAddress = '[email protected]' Where ContactID = 6 --AUDITANDO COMANDO DELETE DELETE FROM Production.UnitMeasure WHERE Name = 'Boxes' --AUDITANDO COMANDO INSERT INSERT INTO Production.Location Magazine',0.00,0.00,GETDATE()) VALUES ('SQL Os dados foram armazenadados em um arquivo que foi gerado na pasta C:\Auditoria. Veja Figura 27. Figura 27. Arquivo de auditoria gerado em um file. Vamos vizualizar os dados auditados utilizando a função fn_get_audit_file, que é responsável em retornar as informações de um arquivo de auditoria. Execute o script da Listagem 03. M V T e c h | 212 SQL Server: Além do Conceito Blog Post Collection /*Retorna informações de um arquivo de auditoria Sintaxe: fn_get_audit_file ( file_pattern, {default | initial_file_name | NULL }, {default | audit_file_offset | NULL } ) */ SELECT convert(varchar(10),event_time,103) as [Data], --Data e hora em que a ação auditável é acionada convert(varchar(12),event_time,114) as [Hora], --Data e hora em que a ação auditável é acionada server_instance_name as [Nome Instância], --Nome da instância de servidor no qual a auditoria ocorreu database_name as [Nome do Banco], --O contexto do banco de dados no qual a ação aconteceu. Permite valor nulo. Retorna NULL para auditorias realizadas no nível de servidor. server_principal_name as [Login], --Logon atual. Permite valor nulo object_name, --O nome da entidade na qual a auditoria ocorreu. statement as [Consulta Executada], file_name as [Caminho do Arquivo] FROM fn_get_audit_file('C:\Auditoria\TargetFileSSMS_D59592D14057-49EB-A421CF2DF6BB2F47_0_129603920978160000.sqlaudit',DEFAULT,DEFAULT) CONCLUSÃO Uma parte essencial de qualquer estratégia de segurança de dados é um plano de segurança que possui regras com a capacidade de rastrear quem acessou ou tentou acessar dados, mas para ter essas informações precisamos realizar auditorias regulamente. Isso permite ao DBA a capacidade de detectar prevenir qualquer ação maliciosa, acessos ilegítimos. Vimos no decorrer do artigo como criar uma auditoria nos mais diversos seguimentos, vimos também que o SQL Server Audit é uma ferramenta poderosa que os DBA’s podem utilizar para coletar quase todas as atividades que acontece dentro dos nossos servidores ou banco de dados ou um objeto especifico. REFERÊNCIAS Compreendendo a auditoria do SQL Server http://msdn.microsoft.com/pt-br/library/cc280386.aspx Como criar uma auditoria no nível do banco de dados M V T e c h | 213 SQL Server: Além do Conceito Blog Post Collection http://msdn.microsoft.com/pt-br/library/cc280425.aspx Como criar uma auditoria do nível de servidor http://msdn.microsoft.com/pt-br/library/cc280426.aspx Auditing in SQL Server 2008 http://msdn.microsoft.com/en-us/library/dd392015(v=sql.100).aspx sys.server_audits (Transact-SQL) http://msdn.microsoft.com/pt-br/library/cc280727.aspx M V T e c h | 214 SQL Server: Além do Conceito Blog Post Collection Performance e Desempenho System Monitor & SQL Profiler É muito comum nos dias de hoje enfrentarmos problemas com desempenho no trabalho ou até mesmo no conforto de nossa casa. Você pode está se perguntando como assim? Imagine a seguinte situação: Uma turma de amigos resolveu marcar um encontro on-line para disputar aquele jogo que acabou de ser lançado. Caso você não tenha uma boa placa de vídeo, memória e um processador mais ou menos a reuniãozinha vai ter que ficar para outro dia. Pois o jogo vai ficar lento, a imagem no seu monitor vai ficar renderizando dentre outas coisas. Falando no mundo do banco de dados, infelizmente vivemos sujeitos a falhas de hardware, bloqueio de transações, paginação, dentre outras coisas que acarretam na degradação das nossas aplicações. Resumindo isso tudo que eu disse é exatamente quando o Service Desk da sua empresa recebe aquelas ligações: “O meu sistema não abre nada!!”, “Tá muito lento não consigo trabalhar” ou melhor “A culpa é da TI”. Diante dessa situação, vou abordar nesse artigo como monitorar seu ambiente de SQL Server e a diagnosticar tais problemas através de estudo de caso prático. O desafio é reunir o System Monitor com o SQL Profiler de uma maneira coerente que nos permita fazer uma análise eficiente. Vou criar um cenário fictício a fim de ajudar na compreensão dos conceitos. Imaginemos que somos funcionários da AdventureWorks e parte das atribuições destinas a nós dentro da empresa, inclui ficarmos encarregados de monitorar o ambiente de produção. Ou seja, verificar o desempenho do banco de dados como um todo. Por exemplo: Analisar se está tendo I/O no disco, como está o processador ou a memória do servidor, quantas conexões estão ativas, e assim por diante. Ultimamente nosso atendimento nível 01 está recebendo muitas ligações reportando problemas de lentidão com as aplicações. Resolvemos então investigar o motivo dessas reclamações. O QUE É O S YSTEM M ONITOR ? A primeira coisa que vamos fazer é utilizar o System Monitor, para coletar as informações do servidor de banco de dados. O System Monitor mostra graficamente os dados em tempo real de desempenho, incluindo a utilização do processador, cache, fila de impressão, sincronização, uso da largura de banda e milhares de outras estatísticas. Ele utiliza uma arquitetura de sondagem para capturar e registrar dados numéricos expostos pelos aplicativos. O DBA escolhe os contadores a serem capturados para análise de acordo com a análise que ele necessita fazer. No nosso caso vamos escolher os contadores que nos ajudará a identificar o motivo da queda de desempenho nas aplicações. N OTA 1: M V T e c h | 215 SQL Server: Além do Conceito Blog Post Collection A cada nova versão do Windows às vezes você tem que procurar as ferramentas que utilizava anteriormente em um lugar diferente. Porque a Microsoft resolveu mudar o nome da ferramenta ou mudou de lugar. Por exemplo, o System Monitor o pessoal que trabalha com TI há muito tempo conhece esse utilitário como “Perfmon”, “Performance Monitor” ou “System Monitor”. O nome “Perfmon” foi dado porque umas das formas de iniciar esse programa é acessando o menu iniciar > executar e digitando na caixa de texto: perfmon.exe. (Fim Nota1) No entanto para entendermos como obter as informações desejadas é importante compreender os três níveis fundamentais para os critérios de monitoramentos. Estes níveis são: object, counter e instance. Veja a Figura 01. Figura 01. Contadores de desempenho do Performance Monitor. OBJECT: Um object é um componente, aplicativo ou subsistema dentro de um aplicativo. Por exemplo, Processor, Network Interface e SQLServer:Databases são todos objects. COUNTERS: Counters são um subconjunto de um object. Para um determinado object, você pode ter vários contadores. Por exemplo, o object Processor tem vários contadores para escolher: % Processor Time, % User Time, Interrupts/sec, etc. INSTANCES: Cada counter pode ter uma ou mais instances . Usando o exemplo acima do object Processor, o %Processor Time teria 47 instâncias de um sistema - um para cada processador (0 até 47). Caso necessite, você tem a capacidade de monitorar apenas uma instância de um counter de dados. M V T e c h | 216 SQL Server: Além do Conceito Blog Post Collection N OTA 2: Lembrando que para que os dados sejam coletados corretamente os únicos tipos de dados permitidos pelo System Monitor são numéricos. (Fim Nota 2) Antes de criarmos nosso primeiro Data Collector Sets queria chamar atenção para três contadores em especial. São eles: System: Processor Queue Length, Network Interface: Output Queue Length e Physical Disk: Avg Disk Queue Length. Se identificarmos alguma anormalidade neles, teremos sérios problemas no sistema. System: Processor Queue Length: Este contador, ao invés de avaliar o uso de um único processador, avalia o enfileiramento de threads aguardando oportunidade de execução em todos os processadores. Se ele excede 02 theads por cada processador durante períodos contínuos ou durante um período de monitorização de 24 horas, você poder ter um gargalo de CPU. Por exemplo, se você possui 06 CPU´s no seu servidor, o valor deste contador não deve ultrapassar quanto? A resposta é 12, que equivale ao seguinte cálculo = 06 x 02 = 12. O resultado é a multiplicação de 06 CPU's com 02 theads(valor aceitável por processador). Se este valor é ultrapassado por um período muito extenso e constante, pode indicar que seus processadores não estão mais suportando a carga do sistema. Network Interface: Output Queue Length: Este contador de desempenho indica o tamanho da fila de pacotes de saída. Ou seja é quantos pacotes estão sendo mantidos em uma fila, esperando para ser enviada a partir da placa de rede para rede. Geralmente esse valor é zero. Como regra geral, se o Output Queue Length for superior a 2 por um período de 10 minutos ou mais de uma vez, provavelmente você tem um problema de desempenho de rede e isso está causando gargalo na rede. As possíveis causas desse problema pode estar em várias coisas como por exemplo: uma placa de rede lenta, um problema de rede, um problema no hub ou switch, pode ser que o SQL Server é muito. muito ocupado e a carga é demias para placa de rede ou até a própria rede. Physical Disk: Avg Disk Queue Length: Uma thread pode fazer muitos pedidos de uma vez só ao IO Manager(O IO Manager é orientado a pacotes. Resumindo em poucas palavras, sua função é receber os pedidos de leitura/gravação dos processos, transformar estes pedidos em um pacote chamado de IRP – IO Request Packet, e encaminhar este pacote ao driver responsável. Após feita essa operação, o driver devolverá o IRP ao IO Manager com as informações de como foi o processamento) sem esperar que a primeira seja completada. O IO Manager não irá recusar esses pedidos, mas irá organizá-los numa fila, pois o disco só faz uma coisa de cada vez. O comprimento médio dessa fila é o "Avg Disk Queue Length". O contador Avg. Disk Queue Length se for superior a dois por períodos contínuos (mais de 10 minutos ou mais durante o período de monitoramento 24 horas) para cada unidade de disco em um array, então você pode ter um gargalo de I/O para esse array. Você precisará calcular este valor, porque o Performance Monitor não sabe quantas unidades físicas estão no seu array. Por exemplo, se você tem um array de 6 discos físicos e o Avg Disk Queue Length do disco é de 10 para uma disposição particular, então o Avg. Disk Queue Length para cada unidade é de 1,66 (Cálculo: 06/10 = 1,66), que está bem dentro da 2 recomendado por disco físico. M V T e c h | 217 SQL Server: Além do Conceito Blog Post Collection Após a compreensão dos níveis e aprendermos um pouco mais sobre contadores, poderemos em fim criar o chamado Data Collector Sets, que nada mais é do que um bloco de monitoramento onde vamos colocar nossos counters. A grosso modo é um conjunto de dados personalizados onde você decide quais atividades serão monitoradas C OMO CRIAR UM D ATA C OLLETOR S ETS ? Quando você usa o System Monitor, é possível ver os contadores de desempenho em tempo real. O Data Collector Sets pode gravar estes dados para que você possa analisá-lo mais tarde. Caso tenha um problema de desempenho ou deseja analisar e, possivelmente, melhorar o desempenho de um servidor, você pode criar um Data Collector Set para recolher dados de desempenho. No entanto, para a análise ser útil, aconselho a coletar e salvar os registros dos dados no momento da queda de desempenho. Mas para que fazer isso? Por que podemos comparar como ficou o desempenho antes de depois dos ajustes. P ARA CRIAR UM D ATA C OLLETOR S ETS PERSONALIZADO , SIGA OS PASSOS ABAIX O : Para iniciar o Performance Monitor clique em Iniciar >Executar e digite: perfmon.exe; Clique em Data Collector Sets > User Defined, com o botão direito do mouse escolha New e em seguida Data Collector Sets. Veja a Figura 02; Figura 02. Primeiro passo para criar Data Collector Sets. M V T e c h | 218 SQL Server: Além do Conceito Blog Post Collection O wizard para criação do Data Collector Sets irá aparecer socilitando que você digite um nome. Logo após a escolha do nome, teremos duas opções: Create from a template (Recommentded) e Create manually (Advanced). A opção default é Create from a template (Recommentded), mas no nosso contexto vamos criar manualmente os contadores que queremos monitorar. Deste modo, selecione a segunda opção e clique em Next. Veja a Figura 03; Figura 03.Wizard Data Collector Sets Agora devemos escolher qual tipo de dados iremos incluir no Data Collector Set. A opção Create data log > Performance Counter já vem selecionada por default, vamos mantê-lo assim. Clique em Next. (Figura 04); M V T e c h | 219 SQL Server: Além do Conceito Blog Post Collection Figura 04. Criar Data Collector Sets Na próxima tela encontramos as seguintes opções: Performance Counter, Event Trace Data e System configuration information. Selecione Performance Counter. Essa opção permitirá escolher qualquer contador disponível no Performance Monitor. Feito isso clique em Next; Clique no botão Add. Selecione os contadores de performance que você deseja. Vamos monitorar a fila atual dos discos (PhisicalDisk\Current Disk Queue Length) e o processador (Processor \%Processor time). Em seguida clique em OK. Observe a Figura 05; M V T e c h | 220 SQL Server: Além do Conceito Blog Post Collection Figura 05. Counter PhysicalDisk Depois de incluir os contadores, o próximo passo é definir qual o intervalo que eles serão monitorados. Veja na Figura 06 que existem duas opções a serem configuradas: Sample interval e Units. Em Sample interval iremos deixar o número 15 e em Units informaremos seconds. Isso irá definir que de 15seg em 15seg será coletadas as informações referente aos contadores adicionados no passo anterior. Clique no botão Finish. M V T e c h | 221 SQL Server: Além do Conceito Blog Post Collection Figura 06. Intervalo de tempo do Data Collector Sets Depois de criar um Data Collector Set você pode salvá-lo no diretório padrão (C:\PerfLogs\Admin\HostName_AnoMesDia) ou escolher outro local da sua preferência. Veja na Figura 07 que o podemos visualizar o caminho completo ao selecionarmos o SQLMagazine em Data Collector Sets. Figura 07. Diretório Padrão do Data Collector Sets Com isso nosso coletor de dados está pronto. Para iniciar a armazenamento das informações basta clicar com o botão direito no Data Colletor Set > SQLMagazine e escolher opção Start. Observe a Figura 08. M V T e c h | 222 SQL Server: Além do Conceito Blog Post Collection Figura 08. Iniciar Data Collector Sets Para verificarmos se a coleta começou, selecione Reports > User > Defined >SQL Magazine. Veja a Figura 09. Figura 09. Relatório Performance Monitor M V T e c h | 223 SQL Server: Além do Conceito Blog Post Collection M V T e c h | 224 SQL Server: Além do Conceito Blog Post Collection SQL SERVER PROFILER O Microsoft SQL Server Profiler é uma interface gráfica para a funcionalidade de Rastreamento, com ele você pode capturar a atividade gerada por uma carga de trabalho em uma instância do SQL Server ou do Analysis Service. Podemos utilizar os dados capturados para monitorar os erros de uma instância ou problemas de concorrência, como também capturar dados que são usados para otimizar o desempenho das consultas que são executadas no ambiente, seja ele de produção ou de teste. Para dar continuidade na resolução do problema de performance na aplicação da empresa AdventureWorks vamos utilizar o Profiler. Vamos criar um trace e fazer uma interseção entre os contadores do Performance Monitor com os dados retornados no trace. O QUE É O T RACE ? SQL Server Profiler é o responsável por criar o chamado Trace. Estes traces incluem todos os scripts T-SQL que são executados simultaneamente no SQL Server, quanto tempo eles estão levando, o tipo de bloqueios sendo usado,e quaisquer erros que possam ocorrer no servidor monitorado. Como o Trace contém todos os scripts T-SQL em execução no SQL Server, muitas vezes tende a se tornar consideravelmente grande. Por isso, é sempre uma boa prática capturar apenas os dados que são realmente necessários para análise. Embora você possa criar um trace usando Transact-SQL (T-SQL), é mais comum usar SQL Server Profiler para isso. E como fazer isso? Você pode iniciar o SQL Server Profiler através do menu File >New Trace do SQL Server 2008 e em seguida se conectar em uma instância para começar a configurar um Trace. Veja na Figura 10. M V T e c h | 225 SQL Server: Além do Conceito Blog Post Collection Figura 10. Criação Trace Todo trace é obrigado a ter um nome e pelo menos um evento. Podemos especificar várias propriedades para um Trace, como por exemplo: nome, modelo, hora de parada, tamanho máximo do arquivo e etc. Veja Figura 11 . Figura 11. Propriedades Trace M V T e c h | 226 SQL Server: Além do Conceito Blog Post Collection Muitas pessoas ignoram os Templates que o SQL Server Profiler fornece. O conhecimento sobre cada um deles nos permite fazer uma análise útil dos traces. O SQL Server Profiler oferece esses modelos de rastreamento predefinidos que permitem facilmente configurar as event classes que provavelmente especificaremos no trace. Na tabela 1 descreve os templates prontos que pode ser utilizado para rastreamentos sem qualquer modificação ou como ponto de partida para um novo onde podemos adicionar colunas e eventos diferentes do padronizado. Template Blank Objetivo Um trace está vazio, ou seja, não possui nenhum evento ou coluna selecionados para o rastreamento. Permite criar um rastreamento inteiro a partir do zero. SP_Counts Captura cada stored procedure executada para determinar o quanto cada procedure está sendo executada. Standard É o template mais comum para começar pois já possui alguns eventos slecionados. Captura os seguintes eventos: Security Audit, Sessions, Stored Procedures e TSQL. TSQL Captura uma lista de todas as stored procedures e ad hoc SQL batch executados, mas não inclui estatísticas de desempenho. TSQL_Durantion Captura a duração de cada stored procedure e ad hoc SQL batch executado. TSQL_Grouped Captura login e logout, junto com as stored procedures e todas as instruções Transact-SQL no momento em que foram emitidos. Use para investigar consultas de um determinado cliente ou usuário. Não inclui dados de desempenho. TSQL_Locks Captura informações de bloqueio e deadlock, como blocked processes, deadlock chains, gráficos de deadlock, lock escalation e lock timeouts. TSQL_Replay Capta informações detalhadas sobre o Transact-SQL . Se é necessário o rastreamento pode repetido nos servidores ou diferentes. Este template é comumente usado para fazer testes de carga e regressão. Por exemplo: realizar testes de benchmark. TSQL_SPs Capta informações detalhadas sobre todos as Stored Procedures em execução. Use para analisar os passos de componentes dos procedimentos armazenados. Adicione o evento SP: Recompile se você suspeitar que os procedimentos estão sendo recompilados. Tuning Captura as informações sobre procedimentos armazenados TransactSQL e execução do lote. Use para produzir saída do trace que o Database Engine Tuning Advisor pode usar como uma workload para ajustar bancos de dados. Tabela 1. Descrição Templates. Por padrão, quando um trace é iniciado usando o SQL Profiler, todos os eventos aparecem em uma grid dentro da interface. Podemos observe na Figura 12 como os eventos são listados no Trace. M V T e c h | 227 SQL Server: Além do Conceito Blog Post Collection Figura 12. Events Selection N OTA 4: Podemos salvar os dados de um trace em uma tabela, em um arquivo ou em ambos. (Fim da Nota 4) Você pode encontrar mais de 200 eventos que podem ser capturados no Trace SQL. A principal ação para configurar um rastreamento é a seleção do conjunto de eventos que precisa ser monitorado. Tais eventos são classificados em 21 grupos, alguns podem contem mais de 40 eventos. Os grupos de evento disponíveis estão listados na Tabela 2. Event Group Broker CLR Cursors Database Deprecation Errors and Warnings Objetivo 13 eventos para mensagens, filas e conversações do Service Broker. 01 evento para o carregamento de Common Language Runtime(CLR) assembly. 07 eventos para criação, acesso e remoção de cursores. 06 eventos para crescimento/diminuição (grow/shirink) de arquivos de dados/log (data/log), bem como mudanças de estado do Database Mirroring. 02 eventos para notificar quando um recurso deprecated é usado dentro da instância. 16 eventos para erros, avisos e mensagens de informação que estão sendo registradas. Eventos para detectar páginas suspeitas, processos bloqueados e estatísticas ausentes em colunas. M V T e c h | 228 SQL Server: Além do Conceito Blog Post Collection Full Text 03 eventos para monitorar o andamento do progresso de um índice full text. Locks 09 eventos de aquisição, “escalation”,liberação e deadlocks. OLEDB 05 eventos para distributed queries (consultas distribuídas) e chamadas de stored procedure. Objects 03 eventos que monitoram quando um objeto é criado, alterado ou eliminado (dropped). Performance 14 eventos que permitem capturar “show plans”, uso de diretrizes de plano e paralelismo. Este grupo de eventos também permite capturar consultas full text. Progress Report 01 evento para progresso de criação de índice online. Query Notifications 04 eventos para monitorar os parâmetros, subscriptions e templates de notificação de consultas. Scans 02 para monitorar quando uma tabela ou índice é percorrido. Security Audit 44 eventos para monitorar o uso de permissões, impersonation, alterações em security objects (objetos de segurança),ações de gerenciamento executadas em objetos, start/stop de uma instância e backup/restore de um banco de dados. Server 03 eventos para a montagem de uma fita, alterar para a memória do servidor e fechar um trace file (arquivo de rastreamento). Sessions 03 eventos para conexões existentes quando o trace inicia, assim como para monitorar a execução de logon triggers e função de classificação no Resource Governor. Stored Procedures 12 eventos para execução de uma stored procedure, cache usage, recompilação e instruções dentro de um procedimento armazenado (stored procedure). Transactions 13 eventos para begin, save, commit e rollback de transações. TSQL 09 eventos para execução de chamadas ad hoc T-SQL ou XQuery. Evento para um lote SQL inteiro, assim como para cada instrução dentro de um lote. User Configurable 10 eventos que você configurar com o SQL Trace. Tabela 2. Conjunto de Eventos. Os grupos mais utilizados são: Locks, Performance, Security Audit, Stored Procedures, e TSQL. Os grupos de evento Stored Procedures e TSQL geralmente são capturados com eventos do grupo Performance para ter um parâmetro e solucionar problemas de desempenho de consulta. O grupo de eventos Security Audit é usado para definir auditoria rapidamente entre uma variedade de eventos de segurança embora a nova “feature” de especificação de auditoria forneça recursos mais seguros e flexíveis. Por fim os eventos do grupo Locks são comumente usados para solucionar problemas de concorrência. Como dito anteriormente, é preciso ter cuidado com quais eventos monitorar, pois alguns deles podem ter uma carga significativa em uma instância. Os eventos que se deve ter muito cuidado são: Performance | Showplan M V T e c h | 229 SQL Server: Além do Conceito Blog Post Collection Stored Procedures | SP: StmtCompleted Stored Procedures | SP: StmtStarting TSQL | StmCompleted TSQL | StmStarting Esses grupos de eventos devem ser incluídos em um trace se e somente se, estiverem em conjunto com um ou vários filtros restritivos, que limite o trace a um único objeto ou string. C OMO APLICAR FILTROS NO SQL P ROFILER ? Após toda essa explicação sobre o que é Profiler, trace, template e grupo de eventos vamos ver como adicionar filtros em um trace para finalmente começarmos a por a mão na massa e resolvermos o problema da AdventureWorks. Um filtro é essencialmente uma cláusula WHERE aplicada nos dados na API do SQL Trace. Os filtros permitem especificar vários critérios a serem aplicados nas colunas de dados. As colunas que possuem “character” (dados alfanuméricos) permitem que filtros sejam definidos em uma string, usando LIKE ou NOT LIKE, que podem conter um ou mais caracteres curingas. Ver Figura 13. Figura 13. Aplicando filtros no Trace. M V T e c h | 230 SQL Server: Além do Conceito Blog Post Collection As colunas de dados baseadas em tempo permitem especificar maior que ou menor que. As colunas de dados numeric permitem especificar igual, diferente, maior ou igual e menor ou igual. As colunas de dados binários não podem ser filtradas. Múltiplos filtros para uma única coluna são tratados com a condição OR. Por outro lado os filtros que possuem várias colunas são tratados com a condição AND. Você pode iniciar, parar e fazer uma pausa em um trace. Depois que foi iniciado o SQL trace retorna os eventos correspondentes a sua necessidade e descarta os eventos que não correspondem aos critérios dos filtros selecionados. Quando um trace é parado, toda a coleta de eventos termina e, se o trace for reiniciado, todos os dados anteriores do trace são apagados da tela do Profiler. Caso queira suspender a coleta de dados temporariamente, você pode pausar o trace. Quando tirar do pause os eventos subsequentes são anexados no final da tela do Profiler. P ERFORMANCE X M ONITORAMENTO O SQL Trace é usado para coletar informações que ocorrem dentro de uma instância do SQL Server. O System Monitor é usado para coletar “performance counters” que fornece o estado dos recursos de hardware e outros componentes em execução no servidor. O SQL Server não pode funcionar sem acessar os recursos de hardware. O estado desses recursos afeta o funcionamento de um servidor SQL Server. Por exemplo, uma query pode estar sendo executada lentamente, mas o Profiler só informa o quanto ela está lenta. Porém, adicionando os contadores de desempenho (performance counters) você poderia encontrar a razão que estaria fazendo a query estar lenta. Nesse caso o motivo é porque não existem recursos de processamento suficientes. Embora seja possível diagnosticar um problema usando somente System Monitor ou o SQL Trace, quando usamos simultaneamente os dois conjuntos de dados ambos fornecem o contexto para qualquer análise. D ICA : Você só poderá correlacionar um “couter log” (System Monitor) com um “trace file” (SQL Profiler) se tiver capturado a coluna de dados StartTime no trace. C RIANDO T RACES Vamos configurar um trace para estabelecer um parâmetro de desempenho para verificar a execução das querys no banco de dados afim de descobrirmos o motivo de lentidão na aplicação. Para fins de demonstração adotaremos o banco exemplo da Microsoft o AdventureWorks. Caso ainda não os possua você poderá baixar as bases de dados AdventureWorks2008 e AdventureWorksDW2008 no site do Code Plex. M V T e c h | 231 SQL Server: Além do Conceito Blog Post Collection Inicie o Profiler. Selecione File > New Trace e conecte-se em sua instância. Especifique o nome do para: SQL Magazine Trace, template: Blank e opções para salvar em um arquivo, como mostrado na Figura 14. Figura 14.Edição do Trace. Clique na guia Events Selection. Marque os eventos Lock: DeadLock graph e TSQL: SQL:BatchCompleted. Ver Figura 15. M V T e c h | 232 SQL Server: Além do Conceito Blog Post Collection Figura 15.Selecionando os Events Selection Clique em Column Filters e especifique o filtro DatabaseName: AdventureWorks e Duration > Greater than or equal: 10000. Ver Figura 16. Figura 16. Editando os filtros do trace. M V T e c h | 233 SQL Server: Além do Conceito Blog Post Collection Clique em Run. Inicie o System Monitor clicando em Iniciar > Executar. Digite: perfmon.exe. Crie um Data Colletor Sets e adicione os seguintes contadores: PhisicalDisk\Current Disk Queue Length, PhisicalDisk\%Disk Time e Processor\%Processor Time. Inicie o Data Collector Sets. Abra o SQL server Management Studio(SSMS), conecte-se na instância e execute as seguinte query. USE AdventureWorks GO --CRIAÇÃO DA TABELA DE TESTE CREATE TABLE TabTeste( ID INT IDENTITY(1,1) PRIMARY KEY, Nome VARCHAR(250) DEFAULT NEWID() ) -- INSERT DE 10000 REGISTROS SET NOCOUNT ON GO INSERT INTO TabTeste DEFAULT VALUES GO 10000 Comente o código anterior e escreva as seguintes linhas de código e execute. DECLARE @I INT SET @I = 0 WHILE @I < 1000000 BEGIN IF EXISTS (SELECT ID FROM TabTeste WHERE ID = @I) BEGIN PRINT 'ENTROU NO LOOP' END SET @I = @I + 1 END GO Abra uma new query e execute o código a seguir. M V T e c h | 234 SQL Server: Além do Conceito Blog Post Collection /*Listagem 1 – “Update” em Production.Product */ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE* GO BEGIN TRANSACTION UPDATE Production.Product SET ReorderPoint = 898 WHERE ProductID = 317 WAITFOR DELAY '00:00:11' Adicione mais uma new query e execute o código a seguir: /*Listagem 2 – “Update” em Production.ProductInventory e um “Select” em Production.Product */ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE GO BEGIN TRANSACTION UPDATE Production.ProductInventory SET Quantity = 655 WHERE ProductID = 317 AND LocationID = 1 SELECT Name, ReorderPoint FROM Production.Product WHERE ProductID = 317 Volte para a janela da primeira query e execute o código a seguir: /*Listagem 3 - “Select” em Production.ProductInventory */ SELECT * FROM Production.ProductInventory WHERE ProductID = 317 AND LocationID = 1 M V T e c h | 235 SQL Server: Além do Conceito Blog Post Collection Irá ocorrer um erro de deadlock. Ver Figura 17. Conforme mensagem abaixo: Msg 1205, Level 13, State 51, Line 1 Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. Figura 17. Erro de DeadLock no SSMS . Verifique no Profile o gráfico gerado pelo deadlock. Ver Figura 18. Figura 18.Gráfico do DeadLock . M V T e c h | 236 SQL Server: Além do Conceito Blog Post Collection Pare o Data Collector Sets que você criou no item 8. Pare o Profiler e salve o trace. Inicie o Profile novamente e selecione File > Open > Trace File. Selecione o trace que você salvou. Clique em File > Import Performance Data. Selecione o counter log criado no System Monitor. Na janela Performance Counters Limit Dialog, selecione Processor: %Processor Time, .PhysicalDisk: %DiskTime e Avg.Disk Queue Length. Ver Figura 19. M V T e c h | 237 SQL Server: Além do Conceito Blog Post Collection Figura 19. Performance Counters Limit Dialog. Percorra o trace no painel superior e observe as alterações que ocorreram dentro no gráfico do performance counter e do rastreamento do Profiler. Ver Figura 20. Figura 20.União entre Performance Monitor e o SQL Profiler. M V T e c h | 238 SQL Server: Além do Conceito Blog Post Collection Conforme podemos observar no gráfico da Figura 16 o maior consumo de CPU foi à consulta que contém o loop. À medida que vamos selecionando as linhas do trace o curso que tem no gráfico vai movimentando-se a fim de mostrar exatamente estava acontecendo no banco de dados. Com isso conseguimos identificar que o problema de performance da empresa AdventureWorks é uma consulta mal escrita que está entrando em um loop e mais que isso existe uma outra query que está provocando deadlock os dois problemas juntos acontecendo várias vezes durante o dia acarretou nas constantes reclamações ao nosso suporte de primeiro nível. A solução para esse problema é a correção de ambas as consultas. D ICA *: Os níveis de isolamento afetam a maneira como o SQL Server manipula as transações, assim como a duração dos “locks acquired“(bloqueios adquiridos). O SQL Server possui cinco níveis de isolamento o que estamos utilizando nesse exemplo é o READ SERIALIZABLE. Esse nível de isolamento emula a execução serial das transações, como se todas as transações fossem executadas uma após a outra, em série, em vez de simultaneamente. Nenhuma outra transação pode modificar dados que foram lidos pela transação atual até que a transação corrente terminar. CONCLUSÃO Apresentamos nesse artigo o que é o Performance Monitor, quais os principais contadores de desempenho, como capturá-los e como analisar os resultados obtidos. Vimos também o SQL Profiler, seus principais grupos, templates e filtros. Por fim, podemos observar que a união dessas duas ferramentas nos ajuda a ter uma visão muito mais ampla dos problemas que estão acontecendo na base de dados. Como podemos observar são muitas variáveis a serem consideradas, mas o que vai influenciar na escolha dos contadores ou eventos vai ser o problema que estamos enfrentando. No caso demonstrado no artigo a dificuldade que a empresa enfrentava era perca de desempenho, mas poderia ser a rede mal configurada ou um gargalo de CPU, memória, disco e etc. Por isso, deve-se tomar muito cuidado na hora de averiguar os diversos cenários aparecem no dia a dia, porque a solução do problema vai depender de uma avaliação bem feita. REFERÊNCIAS Monitoring (Database Engine) M V T e c h | 239 SQL Server: Além do Conceito Blog Post Collection http://msdn.microsoft.com/en-us/library/bb510705.aspx SQL SERVER – Introduction to SQL Server 2008 http://blog.sqlauthority.com/2009/04/24/sql-server-introduction-to-sql-server-2008-profiler/ Using SQL Server Profiler http://msdn.microsoft.com/en-us/library/ms187929.aspx SQL Server - Introduction to SQL Server 2008 Profiler. http://blog.sqlauthority.com/2009/08/03/sql-server-introduction-to-sql-server-2008-profiler-2/ SQL Server Profiler Templates http://msdn.microsoft.com/en-us/library/ms190176.aspx Code Plex (Baixar AdventureWorks 2008): http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=18407. Training Kit – 70-432 M V T e c h | 240 SQL Server: Além do Conceito Blog Post Collection Restore Database com SSIS Olá Pessoal! O post de hoje será sobre uma das tarefas fundamentais de um administrador de banco de dados (DBA) que é garantir que os dados possam ser recuperados no caso de um desastre. No nosso dia a dia, adquirimos várias coisas que possam nos deixar tranquilos com nossos bens como por exemplo uma apólice de seguro para carro ou para sua casa. Apesar de caro e rezarmos para nunca usarmos é uma maneira que escolhemos para nos assegurar contra qualquer “imprevisto”. Enfim, voltando para o nosso assunto, os backups são as apólices de seguro contra qualquer eventualidade na empresa em que trabalhamos. O backup será o responsável por recuperarmos os dados que foram perdidos e no final das contas o negócio voltar a fazer as suas operações empresariais rotineiras. Costumo dizer que ele é o responsável pelo “final feliz” de qualquer situação. (rsrs). Muitas vezes precisamos fazer um restore de uma base em um ambiente diferente do que nós temos, seja ele para fins de teste de backup ou para um ambiente de homologação para que a equipe de desenvolvimento faça seus testes antes de subir uma versão nova. Nesses casos existem diversas formas de resolver o problema como fazer um backup remoto e trazer a base para o ambiente que você precisa ou criar um job para fazer um backup copy only e depois fazer o restore a partir do arquivo gerado. Nesse post para de atender essa necessidade criaremos um pacote para fazer um restore através de um FTP que encontra-se em um servidor de domínio diferente para isso utilizaremos o SSIS, WINSCP e um pouco de powershell.No final da criação do pacote, o mesmo ficará assim: M V T e c h | 241 SQL Server: Além do Conceito Blog Post Collection FTP COM W IN SCP Para configurar os FTP devemos primeiro instalar o WinSCP e configurar um site. A imagem abaixo mostra como ficará após essa configuração: Agora vamos criar um arquivo de texto contendo os seguintes passos: Abrir o site criado no WinSCP; Encontrar o arquivo de backup; Copiar o arquivo para o diretório na máquina onde será feito o restore A criação desse arquivo de texto será o que o WinSCP utilizará para pegar o arquivo no diretório que foi definido para o backup ser salvo e levá-lo para a pasta no outro servidor onde será feito o restore. Abra o notepad e coloque o seguinte script: M V T e c h | 242 SQL Server: Além do Conceito Blog Post Collection option batch on option confirm off open FTP_DATABASE get /BACKUP/DATABASE/NOME_DATABASE_FULL_201411301300.BAK S:\RESTORE\RESTORE_DATABASE\ exit Agora com o SQL Server Data Tools aberto vamos colocar um “Execute Process Task” e configurar as propriedades: Executable, Arguments e WorkingDirectory. M V T e c h | 243 SQL Server: Além do Conceito Blog Post Collection Executable Arguments WorkingDirectory C:\Program Files (x86)\WinSCP\WinSCP.exe -script=C:\FTP\ftpdatabase.txt C:\Program Files (x86)\WinSCP E XECUTE P ROCESS T ASK Para alterarmos o nome do arquivo no “.txt” criado no WINSCP, utilizaremos um pouco de powershell. A necessidade da adição desse passo é porque precisamos recuperar o nome do arquivo exato que o FTP irá copiar para o diretório S:\RESTORE\RESTORE_DATABASE. A primeira coisa a fazer é pegar um o “Execute Process Task” e arrastarmos para o Control Flow, conforme imagem abaixo: M V T e c h | 244 SQL Server: Além do Conceito Blog Post Collection Antes de modificarmos o “Execute Process Task”, vamos criar o script para modificarmos o arquivo de texto. A lógica é simples: Vamos abrir o diretório onde encontra-se o “.txt”; Procurar a palavra COLOCARDATAAQUI; Substituir ela por uma data (A data especificada nesse caso é a data que o backup full foi criado); Salvar o arquivo; Abra o Windows PowerShell ISE (http://technet.microsoft.com/en-us/library/dd819514.aspx), conforme a imagem abaixo: O script para modificar o arquivo de texto é: M V T e c h | 245 SQL Server: Além do Conceito Blog Post Collection Script: (Get-Content C:\FTP\ftpdatabase.txt) | ForEach-Object {$_ -replace "COLOCARDATAAQUI", Date).AddDays(-1).ToString("yyyyMMdd")} | (Get- Set-Content C:\FTP\ftpdatabase.txt; Onde: Get-Content = Ler e exibir o conteúdo de um arquivo de texto de forma rápida. ForEach-Object= Fornece uma maneira para percorrer e executar uma ação. Retorna do dia anterior, com o formato ‘yyyyMMdd’ Uma vez feito o script salve o mesmo com a extensão “.ps1”, no nosso caso foi salvo no mesmo diretório que está o arquivo de texto. Clique com o botão direito para abrir a caixa de propriedade do “Execute Process Task” e vamos preencher os valores e argumentos necessário para editar o arquivo. Na opção “Process” do Execute Process Task Editor vamos alterar os campos Executable e Arguments, conforme imagem abaixo: M V T e c h | 246 SQL Server: Além do Conceito Blog Post Collection Executable Arguments C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -command ". 'C:\FTP\ftppowershell.ps1'" C RIAÇÃO VARIÁVEIS NO SSIS Vamos criar algumas variáveis que irão armazenar o nome do arquivo e o diretório que iremos utilizar para fazer o restore. No menu do SSIS, clique em Variáveis ou clique com o botão direito em qualquer lugar do Control Flow e selecione a opção “Variables”. M V T e c h | 247 SQL Server: Além do Conceito Blog Post Collection Clique em 'Add Variable' e atualize os valores nas colunas name, Data Type e Value. Conforme imagem abaixo: F OREACH L OOP C ONTAINER Vamos utilizar um Foreach Loop Container, o mesmo é muito útil em situações onde é necessário percorrer uma pasta para fazer carga de arquivos ou fazer uma tarefa onde terá que verificar uma lista mais de uma vez. Dê dois cliques no Foreach Loop Container Task para abrir a janela de configuração e selecione a opção “Colletion”. Altere o caminho da pasta para “S:\RESTORE\RESTORE_DATABASE” (Crie essa pasta caso não exista). Altere o tipo dos arquivos para *.bak . M V T e c h | 248 SQL Server: Além do Conceito Blog Post Collection Na guia Variable Mappings selecione a variável User::NM_ARQUIVO na coluna Variable. O Index 0 mapeia o resultado do primeiro (e único) enumerador do Foreach. Clique em OK. M V T e c h | 249 SQL Server: Além do Conceito Blog Post Collection E XECUTE SQL T ASK (DELETE DATABASE) Vamos adicionar um “Execute Script Task” para darmos alteramos a base para SINGLE_USER, conforme imagem abaixo: Script: USE MASTER GO IF EXISTS (SELECT 1 FROM SYS.DATABASES WHERE 'NOME_DO_DATABASE') ALTER DATABASE NOME_DO_DATABASE SET SINGLE_USER WITH IMMEDIATE GO M V T e c h | 250 NAME = ROLLBACK SQL Server: Além do Conceito Blog Post Collection Script Task (NM_ARQUIVO) Vamos adicionar a "Script Task" no pacote SSIS e você configurá-lo abrindo o Script Task Editor. Na opção General, você deve fornecer um nome e uma descrição para a tarefa. Em seguida, vá para opção "Script" do editor para configurar as propriedades. A primeira propriedade que você precisa definir é ScriptLanguage. Você pode criar seus scripts em uma das duas línguas: Visual Basic 2010 ou Visual C# 2010. Iremos usar o C#, para o verificarmos se o nome do arquivo e o diretório do backup estão corretos. A próxima propriedade é EntryPoint. Este é o método (específico para a linguagem de script selecionado) que o tempo de execução SSIS chama como o ponto de entrada em seu código. O método Main, na maioria dos casos, deve funcionar bem. As próximas duas propriedades na página Script são ReadOnlyVariables e ReadWriteVariables. Como os nomes sugerem, você digita o nome de todas as variáveis SSIS que você deseja usar em seu script. (Separe M V T e c h | 251 SQL Server: Além do Conceito Blog Post Collection os nomes com vírgulas para múltiplas variáveis de qualquer tipo.) Vamos adicionar a variável User::NM_ARQUIVO a propriedade ReadOnlyVariables e a variável User::CAMINHO_ARQUIVO à propriedade ReadWriteVariables. Como resultado, o meu script C# será capaz de recuperar a o diretório de backup a partir das variáveis. Clique em “Edit Script..”. Será aberta uma página no Visual Studio para programar o que você precisa, no nosso caso vamos editar o método Main(). Script: public void Main() { // TODO: Add your code here String nome; Dts.Variables["CAMINHO_ARQUIVO"].Value Dts.Variables["NM_ARQUIVO"].Value.ToString(); nome Dts.Variables["CAMINHO_ARQUIVO"].Value.ToString(); M V T e c h | 252 = = SQL Server: Além do Conceito Blog Post Collection MessageBox.Show(nome); Dts.TaskResult = (int)ScriptResults.Success; } E XECUTE SQL T ASK (RESTORE DATABASE / USER PERMISSION) Vamos adicionar mais dois “Execute SQL Task”. No primeiro task será a procedure que faz o restore recebendo o diretório como parâmetro. Script: EXECUTE [DBO].[USP_RESTORE_DATABASE] ? E no segundo “Execute SQL Task” será as permissões para o usuário que acessa a base restaurada. M V T e c h | 253 SQL Server: Além do Conceito Blog Post Collection Script: USE NOME_DO_DATABASE GO IF EXISTS (SELECT 1 FROM NOME_DO_DATABASE.sys.database_principals WHERE name = N'user')DROP USER [caedbh] GO CREATE USER [user] FOR LOGIN [user] WITH DEFAULT_SCHEMA=[dbo] GO M V T e c h | 254 SQL Server: Além do Conceito Blog Post Collection SP_ADDROLEMEMBER 'db_datareader', 'user' GO SP_ADDROLEMEMBER 'db_datawriter', 'user' GO E XECUTE P ROCESS T ASK (MODIFY NAME FTP FILE) Por fim, iremos colocar outro “Execute Process Task” para alterar a data colocada no arquivo de texto responsável de passar o nome do arquivo de backup no FTP. O objetivo dessa task é fazer como que da próxima vez que o pacote for executado o powershell contido no objeto “MODIFY FTP FILE” encontre a palavra “COLOCARDATAAQUI”, para isso basta criar outro arquivo “.ps1” e alterar a ordem do script. Script: (Get-Content C:\FTP\ftpdatabase.txt) | ForEach-Object {$_ -replace (Get-Date).AddDays(1).ToString("yyyyMMdd"), "COLOCARDATAAQUI"} | Set-Content C:\FTP\ftpdatabase.txt; Com a modificação do nome do arquivo concluímos o post com a criação do pacote para restore de bases via FTP. Espero que todos tenham gosto e qualquer, duvida ou critica só entrar em contato. M V T e c h | 255 SQL Server: Além do Conceito Blog Post Collection Leandro Ribeiro www.sqlleroy.com Fragmentação do Transaction Log - Parte I Constantemente, apesar de um vasto material sobre o assunto na net, me deparo com problemas de configuração do Transaction Log, tais como: Arquivos de Logs armazenados no mesmo disco que o arquivo de Dados. Uso de nível de RAID não recomendado. Falta de espaço em disco motivado pelo crescimento do arquivo de log. Mas principalmente, Arquivos de Log fragmentados. A fragmentação do Transaction Log é um problema silencioso em seu ambiente e geralmente ocorre devido a configurações erradas para o arquivo do Transaction Log e em muitos casos, a utilização de configuração padrão (1MB para FileSize e AutoGrowth de 10%) para o arquivo de log, através de um CREATE DATABASE simples. Este assunto motivou a última palestra que fiz com meu amigo Marcus Vinícius Bittencourt [Twitter | Blog] no SQL Saturday 147 em Recife e abordarei neste post. Espero que ajude a alguém. INTRODUÇÃO Antes de entrarmos no universo do Transaction Log, preciso fazer uma pequena introdução de como os dados são trabalhados pelo SQL Server. O Database Engine utiliza dois tipos de gravações: Lógica e Física. A gravação lógica ocorre quando os dados são alterados em uma página do Buffer Cache. A gravação física ocorrendo quando a página é armazenada no disco a partir do Buffer Cache. A partir desta afirmação, temos a seguinte lógica de alteração de uma informação: Se o dado a ser alterado não está em memória, ele é lido do disco e armazenado no Buffer Cache. A alteração é efetuada no Buffer cache e a página é marcada como dirty pages (página suja). O Database Engine utiliza o protocolo Write Ahead Log (WAL) para garantir que as dirty pages sejam armazenadas primeiro no Transaction Log antes de serem persistidas em disco. M V T e c h | 256 SQL Server: Além do Conceito Blog Post Collection As dirty pages são armazenadas em disco de modo assíncrono através dos processos Eager Writing, Lazy Writing e Checkpoint. A imagem abaixo, ilustra o que foi dito acima. T RANSACTION L OG De posse da informação de como os dados são persistidos, temos ideia da carga de trabalho do Transaction Log que o caracteriza como um componente crítico do SQL Server. Toda alteração realizada em um Database é registrada nele. Além de registrar as alterações e garantir o ACID, o Transaction Log é utilizado em: Database Mirroring Log Shipping Replicação Transacional ... Não entrarei em detalhes do comportamento do Transaction Log em cada modelo recuperação, pois independente do modelo utilizado, o arquivo de log pode fragmentar. Internamente, o log é dividido em pequenos blocos chamados de Virtual Log Files (VLF). Além de ser a unidade de divisão do Transaction Log, o VLF permite o efeito circular do log através de sua reutilização. M V T e c h | 257 SQL Server: Além do Conceito Blog Post Collection O tamanho do VLF é definido automaticamente variando de acordo com o crescimento do Log. A Tabela abaixo, informa como ocorre a divisão (Fonte: Kimberly Tripp) < 64MB = 4 VLFs > 64MB < 1GB = 8 VLFs > 1GB = 16 VLFs Usando o exemplo de uma carga de dados que force um crescimento do arquivo de Log em 1000MB, podemos ter: Em um Growth de 10 MB => 4 VLFs de 2.5MB => Total de 400 VLFs. Em um Growth de 200MB => 8 VLFs de 25MB => Total de 40 VLFs Em um Growth de 1000MB => Total de 16 VLFs de 62.5MB A partir do exemplo acima, fica claro que uma configuração ruim para o Auto Growth do arquivo de Log gerará muitos VLFs, caracterizando o que chamamos de Fragmentação Interna do Transaction Log. A fragmentação interna causa impactos em todos os processos que utilizam o Transaction Log e nas aplicações. (Sim... seus Updates e Inserts!!!) Lembram que No início do post, informei a configuração default de criação do banco de dados. Lembrase? M V T e c h | 258 SQL Server: Além do Conceito Blog Post Collection Tamanho Inicial = 1MB com Growth = 10%. Imagina um arquivo de log de alguns "Gigas" utilizando a configuração default...Ahhh! Para verificar as informações de VLFs do arquivo de log, utilizamos o comando DBCC LOGINFO. A quantidade de linhas retornadas é justamente a quantidade de VLFs existentes no Database. Abaixo, informações das colunas retornadas pelo comando. Destaque para as colunas: FileSize - Tamanho do VLF em Bytes. FSeqNo - Número que define a sequência de utilização dos VLFs. Status - Em uso = 2, Livre = 0 CreateLSN - LSN no momento da criação dos VLFs. Quando igual a 0 (Zero) são VLFs criados no Create Database. Ok. Já sabemos conceitualmente como o Transaction Log fica fragmentado e como analisar informações internas do arquivo de Log. Mas como resolver a fragmentação? No próximo post, vamos colocar a mão na massa! Até o próximo post! M V T e c h | 259 SQL Server: Além do Conceito Blog Post Collection Fragmentação do Transaction Log - Parte II No post anterior, abordei sobre o Transaction Log, como ocorre sua fragmentação e como podemos identificá-la. Como prometido, neste post vamos verificar como resolver a fragmentação interna do Log. Mãos à massa! Para exemplificar, vou criar os Databases LargeVLF_Full, LargeVLF_Simple e SmallVLF com as seguintes configurações para os arquivos de Log: LargeVLF_Full com Tamanho de 1MB e File Growth de 10% no recovery model FULL. LargeVLF_Simple com Tamanho de 1MB e File Growth de 10% no recovery model SIMPLE. SmallVLF com Tamanho de 8000MB e File Growth de 4000MB no recovery model FULL. M V T e c h | 260 SQL Server: Além do Conceito Blog Post Collection Após criar os Databases, vamos analisar como estão os VLFs dos arquivos de log através do comando DBCC LOGINFO. LargeVLF_Full com 4 VLFs de "256Kb". LargeVLF_Simple com 4 VLFs de "256Kb". SmallVLF com 16 VLFs de 500MB. M V T e c h | 261 SQL Server: Além do Conceito Blog Post Collection Agora, vamos executar o script abaixo em todos os Databases. M V T e c h | 262 SQL Server: Além do Conceito Blog Post Collection Após a criação da tabela e execução dos inserts, vamos analisar como estão os arquivos de log de cada Database. O Database LargeVLF_Full aumentou de 4 VLFs para 259 Observe que no modelo de recuperação Full, o status de todos os VLFs estão igual a 2 (Em uso). M V T e c h | 263 VLFs. SQL Server: Além do Conceito Blog Post Collection D ICA : Você pode verificar o que está retendo o arquivo de log (status = 2) e impedindo a reutilização dos VLFs através das colunas log_reuse_wait e log_reuse_wait_desc na sys.databases. Neste caso, é o Backup de Log! M V T e c h | 264 SQL Server: Além do Conceito Blog Post Collection As possíveis causas de retenção podem ser encontradas neste link. (http://msdn.microsoft.com/enus/library/ms345414%28SQL.105%29.aspx) O Database LargeVLF_Simple aumentou de 4 VLFs para 91 Pela característica do modelo de recuperação Simples, temos os status 0 (Livre) e 2 (Em uso). VLFs. No modelo Simple o log é automaticamente truncado, mas isso não o impede de ficar fragmentado. Cuidado! Observe que o FileSize dos VLFs nos Databases LargeVLF_Full e LargeVLF_Simple são diferentes a cada crescimento. Isto é motivado pela configuração do File Growth em percentual. M V T e c h | 265 SQL Server: Além do Conceito Blog Post Collection O Database SmallVLF continua com os mesmos Apenas o segundo e terceiro arquivo passaram a ser utilizados (Status = 2). M V T e c h | 266 16 VLFs. SQL Server: Além do Conceito Blog Post Collection Podemos afirmar que os Databases LargeVLF_Full e LargeVLF_Simple estão fragmentados! (Utilizo como "referência" o valor máximo de 50 para quantidade de VLFs. Fonte: Kimberly Tripp) E em relação aos impactos das operações de Inserts e Updates mencionados no primeiro post por você Leandro?! O arquivo de log não se beneficia do recurso Instant File Initialization. Quando é necessário o seu crescimento, seus Updates e Inserts ficarão bloqueados até a conclusão do crescimento do arquivo de log. V AMOS TESTAR ! Para este teste, vamos realizar um update em todos os registros da Tabela nos Databases LargeVLF_Full e SmallVLF, medindo o tempo de execução. M V T e c h | 267 SQL Server: Além do Conceito Blog Post Collection A diferença entre os Updates é de 1896ms. Para verificar o que motivou esta diferença, vamos ao Default trace Log (Se não estiver desabilitado!). M V T e c h | 268 SQL Server: Além do Conceito Blog Post Collection Só para realizar o Auto Growth do arquivo de Log do Database LargeVLF_Full foram gastos 1486ms. Dica: Evite crescimentos de arquivo do SQL Server durante o dia! Bem, espero que tenha ficado claro! Voltando para a resolução do problema de fragmentação... Para "arrumar" nosso arquivo de log, devemos realizar os seguintes procedimentos: Backup de Log. Shrink do arquivo de Log. Alteração do File Size e Auto Growth para um tamanho apropriado. Para facilitar minha vida, criei o script "Analise de Fragmentação" que ao ser executado realiza as seguintes atividades: Verifica e exibe os Databases que contenham mais de 50 VLFs. M V T e c h | 269 SQL Server: Além do Conceito Blog Post Collection Exibe o tamanho e o percentual de utilização dos arquivos de log através do comando DBCC SQLPERF(LOGSPACE). Monta através de "Print", os comandos de ajustes para os Databases que apresentam mais de 50 VLFs. Checkpoint. Backup de Log se o modelo de recuperação não for Simple. Shrink (Recuperando o nome lógico do arquivo) Comando para alterar o File Size e File Growth (Recuperando o nome lógico do arquivo) Abaixo o retorno da query. M V T e c h | 270 SQL Server: Além do Conceito Blog Post Collection Após analisar o ambiente e copiar os comandos gerados para uma nova janela de query, informe: File Size e File Growth para os arquivos de Log identificados no script. Execute o script de ajustes em um momento propício, ou seja, em uma janela de manutenção. Execute novamente o script "Análise de fragmentação" para verificar se seu ambiente está normalizado. Fazer o download dos scripts aqui (http://sdrv.ms/YmYbLK) I NFORMAÇÃO ADICIONAL Ter poucos VLFs e de tamanho "considerável" também é prejudicial ao seu ambiente, pois irá impactar na liberação de espaço do arquivo de Log. VLFs de no máximo 400/500MB é o indicado. M ELHORES PRÁTICAS : M V T e c h | 271 SQL Server: Além do Conceito Blog Post Collection Monitore seu ambiente. Escolha o recovery model ideal para cada ambiente e necessidades de negócio. Ajuste a frequência de Backup de Log para controlar o tamanho do seu arquivo de Log. Não faça "BACKUP LOG ... WITH TRUNCATEONLY pois ele quebrará a sequência do Backup de Log. Utilize transações curtas para que não retenha os VLFs por muito tempo. Ajuste apropriadamente o File Size e File Growth do seu arquivo de Log. Monitore seu ambiente. E aí pessoal, como está o seu ambiente... Espero que o post ajude. Até o próximo! M V T e c h | 272 SQL Server: Além do Conceito Blog Post Collection Luciano Moreira luticm.blogspot.com O caso dos snapshots e data cache thrashing Dia 30/06/2011 foi o último dia do Luan Moreno na Sr. Nimbus e durante o almoço estávamos conversando sobre o SQL Server (para variar um pouco), quando ele disse uma frase muito interessante “Quando você lê do snapshot o SQL Server faz a leitura direta no disco”. Fiz uma cara de interrogação e depois dele explicar melhor entendi o que ele quis dizer: quando você tem um snapshot, as páginas do banco de dados de origem não são compartilhadas com as do snapshot dentro do data cache. Muito interessante! O Luan comentou que leu isso junto ao time do SQLCAT (referência fina e confiável), e esta pequena observação que pode passar despercebida me levou a escrever este artigo, onde podemos ter um potencial problema de data cache thrashing. DATA CACHE E O DATABASE SNAPSHOT. Primeiramente vamos analisar o funcionamento do data cache no SQL Server quando utilizado o database snapshot. Por simplicidade criamos uma tabela onde cada registro ocupa uma página e inserimos 20.000 páginas de dados (script 1). S CRIPT 1 – C RIAÇÃO DOS BANCOS DE DADOS USE master go CREATE DATABASE DataCache go USE DataCache go CREATE TABLE Dados (ID INT IDENTITY NOT NULL PRIMARY KEY, Texto CHAR(8000) DEFAULT 'Sr. Nimbus') GO INSERT INTO Dados DEFAULT VALUES GO 20000 M V T e c h | 273 SQL Server: Além do Conceito Blog Post Collection CREATE DATABASE DataCache_Snapshot ON (Name = 'DataCache', filename = 'C:\temp\DataCache_Snapshotshot.mdf') AS SNAPSHOT OF DataCache GO Quando o snapshot é criado um arquivo de dados é utilizado e aparentemente possui o mesmo tamanho do original, mas somente as páginas que foram alteradas desde a criação do snapshot serão levadas para o novo arquivo (sparse file), conforme a figura 01. Então para o banco de dados DataCache_Snapshot um mapa de bits é criado em memória, para o SQL Server saber se deve ler uma página do arquivo original ou do snapshot, indicando onde está a página correta para leitura. (Figura 01 – Sparse file) Neste momento não tivemos alteração alguma, então todas as páginas que precisamos para os dois bancos estão no arquivo original, vamos então executar um DBCC DROPCLEANBUFFERS para limpar o data cache e executar os comandos abaixo. O que você espera em termos de I/O? SCRIPT 2 – CUSTO DE IO PARA AS CONSULTAS SET STATISTICS IO ON DBCC DROPCLEANBUFFERS GO SELECT * FROM DataCache.dbo.Dados SELECT * FROM DataCache_Snapshot.dbo.Dados go M V T e c h | 274 SQL Server: Além do Conceito Blog Post Collection No primeiro select temos o esperado, uma série de leituras físicas (seja read-ahead ou não) colocando as páginas de dados em cache. E a segunda consulta? Já que não houve alterações nos dados nenhuma das páginas estará no novo arquivo, e como todas as páginas carregadas pelo primeiro SELECT estão em cache, então não é necessário ler nada do disco, correto? S CRIPT 3 – R ESULTADO DE IO PARA AS CONSULTAS (20000 row(s) affected) Table 'Dados'. Scan count 1, logical reads 20076, physical reads 51, read-ahead reads 20055, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. (20000 row(s) affected) Table 'Dados'. Scan count 1, logical reads 20075, physical reads 50, read-ahead reads 20075, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Na verdade não! O data cache referencia as páginas através da combinação: banco de dados, arquivo e página (dbid, fileid, pageid). Quando procura por uma página do novo banco de dados que não está em cache, resta a ele fazer uma leitura no disco, referenciando o mapa de bits para saber se deve ler a página do arquivo original ou do novo. Se as consultas forem executadas novamente não será necessária nenhuma operação de I/O, pois as páginas estão em cache. Consultando sys.dm_os_buffer_descriptors (script 4) veremos que temos uma série de páginas “duplicadas”, com diferença apenas no database_id (figura 2). S CRIPT 4 – C ONSULTANDO O DATA CA CHE select * from sys.databases where name like '%datacache%' go select * from sys.dm_os_buffer_descriptors where database_id in (DB_ID('DataCache'), DB_ID('DataCache_Snapshot')) and file_id <> 2 order by page_id, database_id go M V T e c h | 275 SQL Server: Além do Conceito Blog Post Collection Em termos Internals, o SQL Server não reusa a estrutura BUF entre páginas do snapshot e banco de dados, então as páginas ficarão duplicadas em cache, mesmo que não estejam presentes no arquivo de dados do snapshot. Figura 2 – Páginas “duplicadas” em cache DATA CACHE THRASHING Até agora foi apresentado o funcionamento do database snapshot em relação ao data cache, mas qual é o problema que me levou a escrever este artigo? Uma possível pressão no data cache por conta do SQL Server não reutilizar as páginas entre snapshots! Imagine um caso onde um DBA decide manter alguns snapshots do banco de dados (ex.: um snapshot por dia) em um ambiente onde o volume de alterações é pequeno, então o overhead da operação copy-onwrite não é tão significativo. Durante a semana os dados de uma tabela são comparados entre os dias em que o snapshot é tirado, sendo que isso acontece diversas vezes ao dia. Viu o potencial problema? Vamos aos scripts, primeiro vamos definir o tamanho do buffer pool do SQL Server para 1GB e criar mais alguns snapshots. Tendo a tabela 20.000 páginas aproximadamente, temos 8K * 20.000 páginas, aproximadamente 160MB. S CRIPT 5 – C RIANDO DIVERSOS SNAP SHOTS E MAX SERVER MEMORY SP_CONFIGURE 'MAX SERVER MEMORY', 1000 M V T e c h | 276 SQL Server: Além do Conceito Blog Post Collection RECONFIGURE SHUTDOWN go CREATE DATABASE DataCache_Snapshot2 ON (Name = 'DataCache', filename = 'C:\temp\DataCache_Snapshotshot2.mdf') AS SNAPSHOT OF DataCache GO CREATE DATABASE DataCache_Snapshot3 ON (Name = 'DataCache', filename = 'C:\temp\DataCache_Snapshotshot3.mdf') AS SNAPSHOT OF DataCache GO CREATE DATABASE DataCache_Snapshot4 ON (Name = 'DataCache', filename = 'C:\temp\DataCache_Snapshotshot4.mdf') AS SNAPSHOT OF DataCache GO CREATE DATABASE DataCache_Snapshot5 ON (Name = 'DataCache', filename = 'C:\temp\DataCache_Snapshotshot5.mdf') AS SNAPSHOT OF DataCache GO Com cinco snapshots criados, se executarmos uma consulta que obriga o SQL Server a varrer cada página da tabela, será colocado aproximadamente 960 MB no data cache (script 6). Como todas as páginas couberam em memória após a execução dos seis primeiros SELECTs (sim, o I/O foi pesado), se eu executar todas as consultas 10 vezes em seguida o tempo total de execução ficará em torno de 4 segundos. S CRIPT 6 – U TILIZANDO O ESPAÇO D O DATA CACHE DBCC DROPCLEANBUFFERS go SELECT count(*) FROM DataCache.dbo.Dados SELECT count(*) FROM DataCache_Snapshot.dbo.Dados SELECT count(*) FROM DataCache_Snapshot2.dbo.Dados SELECT count(*) FROM DataCache_Snapshot3.dbo.Dados SELECT count(*) FROM DataCache_Snapshot4.dbo.Dados SELECT count(*) FROM DataCache_Snapshot5.dbo.Dados go SELECT count(*) FROM DataCache.dbo.Dados SELECT count(*) FROM DataCache_Snapshot.dbo.Dados SELECT count(*) FROM DataCache_Snapshot2.dbo.Dados M V T e c h | 277 SQL Server: Além do Conceito Blog Post Collection SELECT count(*) FROM DataCache_Snapshot3.dbo.Dados SELECT count(*) FROM DataCache_Snapshot4.dbo.Dados SELECT count(*) FROM DataCache_Snapshot5.dbo.Dados go 10 E se outro snapshot for criado e aumentarmos uma consulta no nosso batch? Com o limite de memória definido para o SQL Server não será possível colocar mais 160MB em cache, restando ao SQL Server começar a tirar as páginas do cache, forçando operações de I/O e claro, diminuindo a expectativa de vidas das páginas em cache (script 7). S CRIPT 7 – D ATA C ACHE THRASHING DBCC DROPCLEANBUFFERS go SELECT count(*) FROM DataCache.dbo.Dados SELECT count(*) FROM DataCache_Snapshot.dbo.Dados SELECT count(*) FROM DataCache_Snapshot2.dbo.Dados SELECT count(*) FROM DataCache_Snapshot3.dbo.Dados SELECT count(*) FROM DataCache_Snapshot4.dbo.Dados SELECT count(*) FROM DataCache_Snapshot5.dbo.Dados SELECT count(*) FROM DataCache_Snapshot6.dbo.Dados go SELECT count(*) FROM DataCache.dbo.Dados SELECT count(*) FROM DataCache_Snapshot.dbo.Dados SELECT count(*) FROM DataCache_Snapshot2.dbo.Dados SELECT count(*) FROM DataCache_Snapshot3.dbo.Dados SELECT count(*) FROM DataCache_Snapshot4.dbo.Dados SELECT count(*) FROM DataCache_Snapshot5.dbo.Dados SELECT count(*) FROM DataCache_Snapshot6.dbo.Dados go 10 O segundo loop que forçou uma série de operações de I/O demorou entre 2:30 min e 3:00 min em minha máquina, uma diferença considerável para os 4 segundos. Se você quiser ver um comportamento diferente, tente alterar a ordem das consultas, para que o SQL Server não favoreça as páginas de alguns bancos por conta do LRU-K. Esse efeito eu chamo de data cache thrashing, pois é similar a um memory thrashing em relação ao paging file. Obviamente foi um exemplo estruturado para mostrar o overhead deste no SQL Server, mas pense no impacto que isso pode causar no seu ambiente quando colocado em paralelo com outros bancos de dados disputando um espaço data cache. Se você cria vários snapshots com o objetivo de acelerar as suas consultas (o que não é justificável), cuidado, você pode ser pego de surpresa pelo caso dos snapshots e o data cache thrashing. Abraços e até um próximo artigo! M V T e c h | 278 SQL Server: Além do Conceito Blog Post Collection Trigger causando deadlocks Na correria do dia eu recebi uma ligação de um DBA questionando-me sobre um problema de deadlock e, mesmo com o dia atolado, eu separei uns minutinhos para ajudá-lo. Bom, vamos ao problema: Cenário: O cliente possui um problema de deadlock em algumas tabelas e depois de adicionar alguns índices o problema deixou de acontecer. Mas o DBA (de forma bem perspicaz) ainda não está satisfeito com o resultado e procurou minha ajuda para uma recomendação mais embasada. P ERGUNTA : INDEXAÇÃO PODE ELIMI NAR PROBLEMAS DE DEADLOCKS ? Resposta: quase isso! Uma indexação correta pode acelerar as consultas e operações que estavam entrando em deadlock, resultando em uma possibilidade menor da situação se repetir, então uma indexação correta pode sim DIMINUIR (não eliminar, talvez somente em um caso ou outro) os deadlocks! É uma abordagem que utilizamos quando estamos lidando com alguns deadlocks que são "by design", isto é, não podemos alterar o código que causa o problema. Segue um script que simula o problema original, foi bater o olho nele que eu já vi o deadlock, mas para você que quer praticar um pouco, coloque o script em um banco qualquer e mãos à obra! USE Inside go IF OBJECT_ID('DeadlockTrigger') IS NOT NULL DROP TABLE [DeadlockTrigger] go CREATE TABLE [dbo].[DeadlockTrigger]( [Codigo] [int] NOT NULL, [Marca] [char](12) NULL, [Numero] [char](12) NULL, [Qtde] [decimal](10, 3) NULL, [Numeracao] [int] NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[DeadlockTrigger] ADD CONSTRAINT [DF_DeadlockTrigger_Numeracao] DEFAULT (0) FOR [Numeracao] GO create trigger [dbo].[trgI_DeadlockTrigger] [dbo].[DeadlockTrigger] for insert as begin M V T e c h | 279 on SQL Server: Além do Conceito Blog Post Collection update DeadlockTrigger set Numeracao = (SELECT MAX(Numeracao)+1 FROM DeadlockTrigger) WHERE Numeracao = (select Numeracao from inserted WHERE Numeracao=0) return end GO Como vocês podem notar acima, a trigger é responsável por definir a numeração sequencial dos registros na tabela, pegando o maior número atual da tabela. E NTÃO PERGUNTO : AONDE ESTÁ O DEADLOC K ? <!-- Se você quiser analisar o problema e descobrir qual o deadlock, pare aqui e vá brincar com o SQL Server --> E NCONTRANDO O DEADLOC K Se utilizarmos o SSMS e executarmos um insert simples (script abaixo), o SQL Server vai inserir um registro na tabela (lock X - exclusivo) e depois executar um select na tabela procurando pelo maior número existente, que atualizará o registro corrente com esse valor. Essa busca é um table scan e como a própria transação possui um bloqueio exclusivo no registro que foi inserido, a trigger funciona que é uma beleza! Veja parte dos planos nas figuras abaixo... M V T e c h | 280 SQL Server: Além do Conceito Blog Post Collection (Figura 01 – Insert seguido do update da trigger) (Figura 02 – Plano do update fazendo alguns table scans) Adicionando um pouco de concorrência no nosso banco de dados, podemos ver o problema acontecendo, para isso basta disparar o script abaixo em conexões diferentes e depois de alguns segundos vamos ver a mensagem: “Msg 1205, Level 13, State 45, Procedure trgI_DeadlockTrigger, Line 3 Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.” WHILE 1=1 BEGIN INSERT INTO DeadlockTrigger (Codigo, marca, numero, Qtde) VALUES (1, 'Sr. Nimbus', '61 30102050', 300) END Quais foram os recursos que entraram em deadlock? Usando o profiler podemos capturar a seguinte informação: M V T e c h | 281 SQL Server: Além do Conceito Blog Post Collection (Figura 03 – deadlock S com X) Analisando a sequência das operações fica evidente que o temos o cenário onde a transação 1 insere um registro e logo depois a transação 2 insere mais um registro. No momento em que a transação 1 volta a executar a trigger e o update faz o select (table scan) a transação 1 fica bloqueada pelo lock exclusivo da transação 2, quando a transação 2 entra para execução ela fica bloqueada pelo lock exclusivo da transação 01. Como resultado temos um deadlock. M INIMIZANDO OS DEADLO CKS A maneira encontrada pelo cliente de minimizar o problema foi criar um índice no campo Numeracao, conforme o script abaixo: CREATE NONCLUSTERED [dbo].[DeadlockTrigger] ( [Numeracao] ASC ) GO INDEX [idx_Numeracao] ON O que muda com esse índice? Ao invés do update da trigger realizar um table scan, ele passa a fazer um index seek no idx_Numeracao, então como o registro é inserido com numeração = 0 (constraint default), ele estará em um ramo do índice diferente do MAX(numeracao), permitindo que a consulta seja feita sem problema de bloqueio entre S e X (visto na figura 03). Então estamos livres do problema? Aparentemente sim, mas basta executar novamente os loops concorrentes que vemos a mesma mensagem 1205! É o mesmo deadlock? Não! Se capturarmos o problema com o profiler veremos o seguinte: M V T e c h | 282 SQL Server: Além do Conceito Blog Post Collection (Figura 04 – deadlock U com X) O problema não está mais com o select MAX(numeracao) do update! Agora o problema está com a atualização dos registros que possuem numeracao = 0, pois em determinado momento podemos ter dois registros com o valor zerado (de transações diferentes) e enquanto o SQL Server está varrendo o índice à procura do objeto (usando o lock de Update) ele vai encontrar um registro bloqueado por outra transação e vice-versa. Então a criação do índice nesse caso somente está mudando um pouco o tipo de deadlock que encontramos, saindo de um X com S para um X com U. E potencialmente, com uma tabela grande, a chance de encontrarmos um deadlock fazendo um table scan é MUITO maior do que utilizando um index seek. Resultado: O cliente pode estar com a falsa impressão de que resolveu o problema de deadlock. O que é muito ruim, pois esse irá se tornar um erro intermitente, daqueles mais chatos de entender. Outra abordagem que o pessoal poderia tentar, e vejo muito por aí, seria tentar evitar o problema do deadlock X com S utilizando uma hint de NOLOCK durante a busca do update, da seguinte forma: ALTER trigger [dbo].[trgI_DeadlockTrigger] on [dbo].[DeadlockTrigger] for insert as begin update DeadlockTrigger SET Numeracao = (SELECT MAX(Numeracao)+1 FROM DeadlockTrigger with (nolock)) WHERE Numeracao = (select Numeracao from inserted WHERE Numeracao=0) return end Dessa forma realmente não veríamos mais deadlocks S com X, mas cairíamos novamente no problema do deadlock X com U e provavelmente com uma freqüência maior que a primeira abordagem, pois sendo um update menos eficiente a transação toda levaria mais tempo, aumentado a chance do problema ocorrer. Concorda? M V T e c h | 283 SQL Server: Além do Conceito Blog Post Collection R ESOLVENDO O PROBLEMA ( DE VERDADE ) Por motivos de negócio ou até históricos é normal vermos algumas soluções que acabam deixando de lado os recursos da ferramenta, que potencialmente são mais eficientes. No caso acima fica patente que a utilização de um campo IDENTITY resolveria o problema do cliente, basta criar a tabela com o script abaixo (e sem a trigger, claro!) que o problema do deadlock vai embora. IF OBJECT_ID('DeadlockTrigger') IS NOT NULL DROP TABLE [DeadlockTrigger] go CREATE TABLE [dbo].[DeadlockTrigger]( [Codigo] [int] NOT NULL, [Marca] [char](12) NULL, [Numero] [char](12) NULL, [Qtde] [decimal](10, 3) NULL, [Numeracao] [int] IDENTITY(1,1) NOT NULL ) ON [PRIMARY] GO Caso a resolução do problema ainda não seja suficiente para convencer o cliente, podemos ver o lado de desempenho da solução com a trigger. Após inserir uma pequena massa de dados (13.000 registros) eu executei um insert e mostro na figura 05 o plano de execução: M V T e c h | 284 SQL Server: Além do Conceito Blog Post Collection (Figura 05 – Plano de execução do insert) Note que aqui estou utilizando a versão inicial do problema (sem o índice), onde um table scan pesa muito no custo relativo de update no batch, isto é, do custo total para se fazer o insert a trigger é responsável por 95%. E a solução com índice versus a solução com o campo IDENTITY, qual será mais barata? Para verificar a resposta dessa questão eu criei o índice idx_Numeracao na tabela e criei a tabela DeadlockTrigger2, que possui um IDENTITY no campo Numeracao e nenhuma trigger. Veja o resultado na figura 06. (Figura 06 – custos relativos) O insert no primeiro caso é responsável por 86% do custo total de batch, enquanto o custo do segundo insert é de 14%. Claramente podemos notar que a segunda abordagem é mais eficiente que a primeira, além de resolver o problema de deadlock, então porque não utilizá-la? CONCLUSÃO M V T e c h | 285 SQL Server: Além do Conceito Blog Post Collection É importante analisarmos com cuidado quando um problema foi efetivamente resolvido, pois paliativos podem nos enganar e criar problemas ainda maiores para o futuro. Sempre que existe uma abordagem de implementação da solução utilizando recursos da própria ferramenta, eu dou preferência a eles, pois existe uma boa probabilidade de e serem mais eficientes e livres de efeito colateral. Espero ter ajudado. Abraços M V T e c h | 286 SQL Server: Além do Conceito Blog Post Collection VARCHAR(MAX) vs. TEXT (Sintaxe?) Como vocês já podem ter visto, nós na Nimbus gostamos de detalhes do SQL Server, quanto mais interno (ou misterioso) mais divertido. Hoje mostro para vocês um pequeno aspecto relacionado aos tipos de dados, que inclusive já encontramos em um cliente e um ajuste gerou um grande e positivo impacto no desempenho do ambiente SQL Server. A dúvida: VARCHAR(MAX) e TEXT são sinônimos no SQL Server? Se você olhar o que o tipo de dados pode armazenar parecem ser idênticos, então se é só uma diferença de sintaxe tanto faz qual eu utilizo, mas levando em conta que o TEXT está marcado como deprecated, e só trocar tudo por VARCHAR(MAX) e correr para o abraço! Calma lá campeão, vamos a um exemplo simples (rode o script 01)... S CRIPT 01 – D UAS TABELAS IDÊNTICAS , VARCHAR(MAX) E TEXT USE tempdb go IF OBJECT_ID('dbo.TabelaTEXT', 'U') IS NOT NULL DROP TABLE dbo.TabelaTEXT GO CREATE TABLE dbo.TabelaTEXT ( ID INT IDENTITY NOT NULL CONSTRAINT PK_TabelaTEXT PRIMARY KEY , Nome VARCHAR(100) NOT NULL DEFAULT ('Sr. Nimbus') , DataRegistro DATETIME2 NOT NULL DEFAULT(SYSDATETIME()) , Texto TEXT NOT NULL DEFAULT (REPLICATE('A', 2000)) ) GO IF OBJECT_ID('dbo.TabelaVARMAX', 'U') IS NOT NULL DROP TABLE dbo.TabelaVARMAX GO CREATE TABLE dbo.TabelaVARMAX ( ID INT IDENTITY NOT NULL CONSTRAINT PK_TabelaVARMAX PRIMARY KEY , Nome VARCHAR(100) NOT NULL DEFAULT ('Sr. Nimbus') , DataRegistro DATETIME2 NOT NULL DEFAULT(SYSDATETIME()) , Texto VARCHAR(MAX) NOT NULL DEFAULT (REPLICATE('A', 2000)) ) GO INSERT INTO dbo.TabelaTEXT DEFAULT VALUES INSERT INTO dbo.TabelaVARMAX DEFAULT VALUES M V T e c h | 287 SQL Server: Além do Conceito Blog Post Collection GO 10000 SELECT ID, Nome FROM dbo.TabelaTEXT SELECT ID, Nome FROM dbo.TabelaVARMAX go Quando você executar o script acima vai encontrar o plano esperado para as duas consultas, um clustered index scan pegando os 10.000 registros. O que pode te pegar de surpresa é o custo relativo, 2% contra 98% (figura 01). Isso mesmo, SÓ essa pequena diferença. Utilizando o STATISTICS IO, vemos o motivo dessa diferença: Table 'TabelaTEXT'. Scan count 1, logical reads 68 Table 'TabelaVARMAX'. Scan count 1, logical reads 3348 (Figura 01 – comparando os planos de execução) Mas qual o motivo dessa diferença? Quando você utiliza o VARCHAR(MAX), caso o seu large object (LOB) caiba dentro da página de dados de 8K (nesse casso os 2.000 bytes cabem), o SQL Server vai favorecer essa opção, diferente do TEXT! Isso é, se você está consultando na maioria do tempo outras colunas que não a sua LOB, o SQL Server está carregando para o data cache páginas com baixa quantidade de registros, minimizando a eficiência do seu cache e consequentemente, o desempenho geral do SQL Server. Então existem diferenças e você pode ver o detalhe com algumas DMVs. M V T e c h | 288 SQL Server: Além do Conceito Blog Post Collection S CRIPT 02 – A NALISANDO AS UNIDADES DE ALOCAÇÃO SELECT OBJECT_NAME(object_id) AS ObjectName , AU.type , AU.type_desc , AU.container_id , AU.filegroup_id , AU.total_pages , AU.used_pages , AU.data_pages FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go (Figura 02 – Comparando AllocUnits) Na figura 02 podemos ver que a tabela com TEXT possui poucas páginas de dados (IN_ROW_DATA), contendo em seus registros ponteiros para unidades LOB onde efetivamente os dados estão. Já no VARCHAR(MAX) as unidades de alocação de LOB_DATA não estão em uso, com used_pages igual a zero (ROW_OVERFLOW pode ser ignorado para esse artigo). Viu a diferença? Pequeno detalhe que pode impactar (e muito!) o seu ambiente. E agora você pode estar se perguntando, como eu altero esse modo de operação? Simplesmente executar um REBUILD do índice não vai fazer com que ele mude seu comportamento. S CRIPT 03 – SP _ TABLEOPTION PARA LARGE VALUES -- SP_TABLEOPTION!! M V T e c h | 289 SQL Server: Além do Conceito Blog Post Collection EXEC sp_tableoption 'TabelaVARMAX', 'large value types out of row', 1 go -- rebuild ALTER INDEX PK_TabelaVARMAX ON dbo.TabelaVARMAX REBUILD go SELECT OBJECT_NAME(object_id) AS ObjectName , AU.type , AU.type_desc , AU.container_id , AU.filegroup_id , AU.total_pages , AU.used_pages , AU.data_pages FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go -- Não?! Outra possibilidade... UPDATE dbo.TabelaVARMAX SET Texto = Texto GO -- E agora, 100%? SELECT OBJECT_NAME(object_id) AS ObjectName , AU.type , AU.type_desc , AU.container_id , AU.filegroup_id , AU.total_pages , AU.used_pages , AU.data_pages M V T e c h | 290 SQL Server: Além do Conceito Blog Post Collection FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go -- A diferença dos custos se manteve? SELECT ID, Nome FROM dbo.TabelaTEXT SELECT ID, Nome FROM dbo.TabelaVARMAX go -- E o espaço das páginas de dados do índice cluster? SELECT OBJECT_NAME(object_id) AS ObjectName , AU.type , AU.type_desc , AU.container_id , AU.filegroup_id , AU.total_pages , AU.used_pages , AU.data_pages FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go -- Organizando a casa... ALTER INDEX PK_TabelaVARMAX ON dbo.TabelaVARMAX REBUILD go SELECT OBJECT_NAME(object_id) AS ObjectName , AU.type , AU.type_desc , AU.container_id , AU.filegroup_id , AU.total_pages , M V T e c h | 291 SQL Server: Além do Conceito Blog Post Collection AU.used_pages , AU.data_pages FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go -- Agora sim... SELECT ID, Nome FROM dbo.TabelaTEXT SELECT ID, Nome FROM dbo.TabelaVARMAX Go -- Diferença ainda existe, mas é gerenciável SELECT OBJECT_NAME(object_id) AS ObjectName , AU.* , P.* FROM SYS.system_internals_allocation_units AS AU INNER JOIN SYS.Partitions AS P ON AU.Container_id = P.Partition_id WHERE Object_ID IN (object_id('TabelaTEXT'), object_id('TabelaVARMAX')) ORDER BY object_id, type go O script acima mostra o uso do sp_tableoption com a opção “large value types out of row”, que definido Segundo o BOL significa: “1 = varchar(max), nvarchar(max), varbinary(max), xml and large user-defined type (UDT) columns in the table are stored out of row, with a 16-byte pointer to the root”, exatamente o que queremos. Um aspecto curioso que me chamou a atenção quando estávamos resolvendo o caso do cliente, e que você vai poder notar no script completo que acompanha o artigo, é que uma vez habilitada essa opção o rebuild do índice NÃO fez a organização que eu esperava. Foi necessário um UPDATE dummy da coluna VARCHAR(MAX) em todos os registros para o SQL Server colocar efetivamente o ponteiro de 16 bytes para o LOB nas sua devida unidade de alocação. Mesmo assim você vai notar que os custos do plano de execução se mantiveram mesmo após o UPDATE, pois não houve nenhuma operação para organizar os registros no índice cluster, então a baixíssima densidade de registros por páginas se manteve, com uma gigante fragmentação interna. Com o UPDATE + REBUILD conseguimos o que queríamos e os planos agora são bem compatíveis! Ainda ficou uma diferença entre o número total de páginas no índice cluster, mas agora essa diferença é pequena e gerenciável, quem sabe não falamos sobre isso em outro post... M V T e c h | 292 SQL Server: Além do Conceito Blog Post Collection Nilton Pinheiro www.mcdabrasil.com.br/ Trabalhando com datas e conversões no SQL Server Uma reclamação bastante comum de muitos desenvolvedores está na aparente dificuldade em se trabalhar com datas e horas no SQL Server, mais especificamente quando usando os tipos de dados datetime e smalldatetime. Eu digo aparente dificuldade, porque a grande verdade é que para trabalhar com data e hora no SQL Server, a primeira coisa a fazer é entender como estes tipos de dados armazenam seus dados. A partir do momento que você entender como o SQL Server armazena e trata esses dados, você verá que trabalhar com datetime e smalldatetime é bastante simples. Então, neste tópico veremos como esses tipos de dados se diferenciam um do outro, como eles armazenam seus dados e como trabalhar com esses dados. Abordaremos também algumas funções internas do SQL Server que simplificam muito o trabalho com estes tipos de dados. O S TIPOS DE DADOS D ATE T IME E S MALL D ATE T IME Estes são dois tipos de dados bastante utilizados no SQL Server para trabalhar com valores data e hora. A diferença básica entre os dois, está na quantidade de bytes utilizados para o armazenamento da data/hora, o range de datas suportadas e suas precisões. Enquanto o DateTime usa 8 bytes para o armazenamento, o SmallDateTime usa apenas 4 bytes e é por essa razão que o DateTime consegue armazenar um range maior de datas e também possui uma maior precisão que o SmallDateTime. O DateTime armazena datas de 1 de Janeiro de 1753 até 31 de Dezembro de 9999 com uma precisão de 3.33 milissegundos ou 0.00333 segundos, sendo os valores arredondados para incrementos de .000, .003 ou .007 segundos, como mostrado na Tabela 1. Datas de Exemplo Arredondamento 01/01/2015 23:59:59.999 02/01/2015 00:00:00.000 01/01/2015 23:59:59.995, 01/01/2015 23:59:59.996, 01/01/2015 23:59:59.997 01/01/2015 23:59:59.997 ou 01/01/2015 23:59:59.998 01/01/2015 23:59:59.992, 01/01/2015 23:59:59.993, 01/01/2015 23:59:59.993 01/01/2015 23:59:59.994 01/01/2015 23:59:59.990 ou 01/01/2015 23:59:59.991 01/01/2015 23:59:59.990 Tabela 1. Exemplos de arredondamento com DataTime M V T e c h | 293 SQL Server: Além do Conceito Blog Post Collection Observe que os horários com milissegundos entre .990 e .991 foram arredondados para .990. Os valores entre .992 e .994 foram arredondados para .993 e os valores entre .995 e .998 foram arredondados para .997 O SmallDateTime armazena datas de 1 de Janeiro de 1900 até 6 de Junho de 2079 com precisão de 1 minuto. Valores SmallDateTime com 29.998 segundos ou menos, são arredondados para o minuto anterior, valores com 29.999, são arredondados para o minuto superior. Alguns exemplos podem ser vistos na Tabela 2. Exemplo Arredondamento 2014-05-08 12:35:29.998 2014-05-08 12:35:00 2014-05-08 12:35:29.999 2014-05-08 12:36:00 Tabela 2. Exemplos de arredondamento com SmallDataTime Um ponto importante para ter sempre em mente é que tanto o DateTime quanto o SmallDateTime representam a data e hora como um valor que é igual ao número de dias decorridos desde a meia-noite do dia 1 de Janeiro de 1900, conhecida como “data base”. No entanto, como descrito anteriormente, o SmallDateTime somente pode representar datas a partir desta data base em diante. Já o DateTime, também pode representar datas que estejam antes de 1 de Janeiro de 1900 e para fazer isso, ele armazena os valores como números negativos. Valores DateTime são armazenados internamente pelo SQL Server como sendo 2 inteiros de 4 bytes (totalizando 8 bytes de armazenamento). Os primeiros quatro armazenam o número de dias decorridos antes ou após a data base. Os outros quatro armazenam a hora do dia representada como unidades de 0.00333 segundos após a meia noite. Já valores para SmallDateTime são armazenados como sendo 2 inteiros de 2 bytes (totalizando 4 bytes de armazenamento). Os primeiros dois armazenam o número de dias decorridos desde 1 de Janeiro de 1900. Os outros dois armazenam o número de minutos desde a meia noite. E NTENDENDO O ARMAZENA MENTO DOS VALORES DA TA E HORA Para entender como os valores data e hora são armazenados no SQL Server, divida o valor data e hora em duas partes a saber: a parte inteira e a parte fracional. A parte inteira representa o número de dias decorridos desde a data base. A parte fracional representa a parte horas, decorridas desde a meia-noite da data base. Para que você possa entender melhor, imagine que estamos em 4 de Janeiro de 1900 ao meio-dia. Internamente, o valor que representa essa data e hora é armazenado como 3.5. Ou seja, o número inteiro três representa o número de dias decorridos desde a data base e a fração 0.5 representa a metade do dia M V T e c h | 294 SQL Server: Além do Conceito Blog Post Collection transcorrido desde a meia-noite. Para simular isso no SQL Server, basta executar a consulta a seguir no SQL Server Management Studio: SELECT CAST(CAST('1900-01-04 12:00' AS DateTime) AS Float) No exemplo, utilizamos a função CAST para converter a string 1900-01-04 12:00 para DateTime e depois para Float. Como resultado temos o valor 3.5 do tipo Float representando então a data. Se usarmos o mesmo SELECT passando como string a data 2015-01-30 12:00, teremos como resultado o valor 42031.5 onde 42032 representa o número de dias decorridos desde a data base e 0.5 a metade do dia desde a meia noite. Uma característica destes dois tipos de dados é que eles não podem armazenar datas sem hora e nem hora sem data. Como consequência, se você armazenar uma data sem informar a parte hora, a parte que representa a hora será definida como 0. Isso será representado como meia-noite utilizando o formato 00:00:00 se estiver utilizando um campo do tipo SmallDateTime ou 00:00:00.000 se estiver utilizando um campo DateTime. Similarmente, se você armazenar apenas a hora sem informar uma data, a parte que representa a data será definida como 0. Isso será representado como 1 de Janeiro de 1900 para ambos os tipos de dados. Para entender melhor, execute o código a seguir no SQL Server Management Studio: CREATE TABLE TB_DATAS ( Parte_Data DateTime, Parte_Hora SmallDateTime) GO INSERT TB_DATAS VALUES ('2015-01-30','15:10') INSERT TB_DATAS VALUES ('11:00','2015-01-30') GO SELECT * FROM TB_DATAS O script cria a tabela TB_DATAS com as colunas Parte_Data (DateTime) e Parte_Hora (SmallDateTime) e resultado de sua execução pode ser visto na Figura 1. No primeiro INSERT, observe que para na coluna Parte_Data é informada apenas a parte referente à data (a hora está como 00:00:00.000) e para a coluna Parte_Hora, apenas a parte referente à hora (a data está como 1900-01-01). No segundo INSERT é feito o processo inverso. Figura 1. Salvando dados em colunas DateTime e SmallDateTime M V T e c h | 295 SQL Server: Além do Conceito Blog Post Collection Observe que para ambos os tipos de dados, para as datas informadas sem a parte hora o SQL Server considerou a hora como sendo 0 ou meia-noite. Já para as datas sem a parte data o SQL Server considerou a data como sendo 1 de Janeiro de 1900. Ou seja, a data base. É importante notar que o mesmo acontece quando você faz um SELECT em um campo data que usa estes tipos de dados. Vejam o exemplo a seguir: SELECT CAST('2015-01-30' AS DateTime) As Parte_Data, CAST('10:00' AS DateTime) AS Parte_Hora SELECT CAST('2015-01-30' AS SmallDateTime) AS Parte_Data, CAST('10:00' AS SmallDateTime) AS Parte_Hora O resultado é mostrado na Figura 2. Figura 2. Exemplo de Select em um campo Data No exemplo, o primeiro SELECT utiliza a função CAST para converter a string representando a data para o tipo DateTime, enquanto o segundo converte para o tipo SmallDateTime. Observe que o primeiro CAST passa uma data sem informar a parte hora (2015-01-30), então o SQL Server entende que a parte hora é meia-noite ou 00:00:00.000. O segundo CAST informa apenas a parte hora (10:00), então o SQL Server entende que a data é 1 de Janeiro de 1900. T RABALHANDO COM A PAR TE DATA Entendido como o SQL Server trata e armazena as datas para estes tipos de dados, vamos ver então como fazer pesquisas com datas no SQL Server. Para um melhor entendimento, considerem uma tabela de pedidos com os registros apresentados na Figura 3. M V T e c h | 296 SQL Server: Além do Conceito Blog Post Collection Figura 3. Dados de exemplo da tabela de pedidos O script para criação da tabela e população dos dados de exemplo encontra-se na Listagem 1. L ISTAGEM 1. S CRIPT PARA CRIAÇÃO E POPULAÇÃO DA TABELA DE PEDIDOS CREATE TABLE TB_PEDIDO( ID_Pedido int, ID_Cliente VarChar(10), Data_Pedido DateTime, Data_Envio SmallDateTime) GO INSERT TB_PEDIDO VALUES (1,'NILTON','2014-02-28 10:00:00.000','2014-02-28 16:20:00') INSERT TB_PEDIDO VALUES (2,'NILTON','2014-02-15 13:58:32.823','2014-02-16 00:00:00') INSERT TB_PEDIDO VALUES (3,'JORGE','2014-02-27 00:00:00.000','2014-02-27 16:00:00') INSERT TB_PEDIDO VALUES (4,'JORGE','2014-02-27 10:15:56.833','2014-02-28 00:00:00') INSERT TB_PEDIDO VALUES (5,'CARLOS','2014-08-10 00:00:00.000','2014-08-10 00:00:00') INSERT TB_PEDIDO VALUES (6,'CARLOS','2014-08-10 10:21:15.637','2014-08-10 17:20:00') Uma pesquisa muito comum quando trabalhamos com data e hora é pesquisar por registros de uma determinada data independente da hora. Usando os dados da tabela de pedidos, um exemplo seria pesquisar por todos os pedidos enviados no dia 10-08-2014. M V T e c h | 297 SQL Server: Além do Conceito Blog Post Collection Se a data na coluna estiver sendo armazenada com a parte hora sendo 0 (como no caso do registro 5), não haverá problemas pois como vemos, quando você pesquisa por uma data sem informar a parte hora, o SQL Server considera a hora como sendo 0 ou meia-noite. Dessa forma buscará por todos os registros que contenham a data 10-08-2014 e a parte hora como 00:00:00. No entanto, como podemos ver nos dados de exemplo, tanto a coluna Data_Pedido quanto a Data_Envio são usadas de forma inconsistente, ou seja, as vezes a parte hora é informada e as vezes não. Isso pode indicar que o objetivo do desenvolvedor era armazenar somente a parte data, mas isso não foi forçado pela aplicação e acabou gerando registros com a parte hora diferente de 0. A conseqüência disso é que se você disparar uma consulta querendo saber todos os pedidos com data de envio igual a 10-08-2014 (sem informar a parte hora), o resultado obtido não será o esperado. O SELECT para a obtenção desses registros seria: SELECT * FROM TB_PEDIDO WHERE Data_Envio = '2014-08-10' Ao executar, o resultado mostra somente o registro 5 quando o desejado seria retornar os registros 5 e 6. Isso acontece porque como a parte hora não foi informada na pesquisa, o SQL Server pesquisará pela data onde a parte hora seja 0. Uma vez que a hora para o registro 6 é 17:20:00, o mesmo não é retornado. Sendo assim, como podemos fazer para contornar esse problema? Se esse tipo de consulta for muito utilizada por sua aplicação, a sugestão é que você passe a trabalhar com range de valores. Exemplo: SELECT * FROM TB_PEDIDO WHERE Data_Envio BETWEEN '2014-08-10' AND '2014-08-10 23:59:59.997' Lembre-se que a cláusula BETWEEN obtém valores que estão entre o primeiro e o segundo valor informado (também conhecidos como limites inferior e superior). Você não pode definir o limite superior como 2014-08-10. Se o fizer, novamente obterá como retorno apenas o registro 5, pois o SQL Server tratará a hora como sendo 0. Observe que no exemplo, o limite superior foi definido como “2014-08-10 23:59:59.997”. Com isso, o SQL Server buscará por todos os registros entre “2014-08-10 00:00:00.000” e “2014-08-10 23:59:59.997”, pegando assim todo o range de horário do dia “2014-08-10” e obtendo então todos os registros deste dia. Veja o resultado na Figura 4. M V T e c h | 298 SQL Server: Além do Conceito Blog Post Collection Figura 4. Dados corretamente retornados Um outro caminho para obter o resultado esperado é usando operadores de comparação >= (maior igual) e < (menor), como demonstrado no código: SELECT * FROM TB_PEDIDO WHERE Data_Envio >= '2014-08-10' AND Data_Pedido < '2014-08-11' Nesse caso o SQL Server interpretará as datas como “2014-08-10 00:00:00.000” e “2014-08-11 00:00:00.000”. Como o filtro busca por registros com data de pedido menor que “2014-08-11 00:00:00.000”, então o SQL Server retornará apenas os registros do dia 10-08-2014 até o horário de 23:59:59.997. F UNÇÕES E C ONVERSÕES Uma prática comum de muitos desenvolvedores é fazer uso de algumas funções internas do SQL Server para simplificar o trabalho com datas e algumas das funções mais comuns estão listadas na Tabela 3. Função DATEDIFF() DATEPART() DATEADD() Descrição Calcula o intervalo entre duas datas. Sintaxe: DATEDIFF (datepart, startdate, enddate ) Exemplo -- Retorna o dia da data especificada SELECT DATEDIFF(day, ‘2014-10-17’, ‘2014-10-18’) Para datepart você pode usar: Year, quarter, Month, dayofyear, Day, Week, Hour, minute, second e millisecond. Retorna partes específicas de -- Retorna o minuto da data especificada uma data. SELECT DATEPART(minute, ‘2014-10-18 15:22:56.567’) Sintaxe: DATEPART (datepart, date) Para datepart você pode usar: Year, quarter, Month, dayofyear, Day, Week, Hour, minute, second e millisecond. Retorna uma nova data -- Adiciona 3 dias à data especificada baseado na adição de um SELECT DATEADD(day, 3, ‘2014-10-18 15:22:56.567’) intervalo para uma data especificada. Sintaxe: Para datepart você pode usar: Year, quarter, Month, DATEADD (datepart, number, dayofyear, Day, Week, Hour, minute, second e millisecond. date) M V T e c h | 299 SQL Server: Além do Conceito Blog Post Collection DAY() MONTH() YEAR() CAST() CONVERT() Retorna um inteiro representando a parte dia de uma data. Sintaxe: DAY (date) Retorna um inteiro representando a parte mês de uma data. Sintaxe: MONTH (date) Retorna um inteiro representando a parte ano de uma data. Sintaxe: YEAR(date) Converte um tipo de dados para outro. Sintaxe: CAST (expression AS data_type) -- Retorna o valor 18 SELECT DAY(‘2014-10-18 15:22:56.567’) -- Retorna o valor 10 SELECT MONTH(‘2014-10-18 15:22:56.567’) -- Retorna o valor 2014 SELECT YEAR(‘2014-10-18 15:22:56.567’) -- Converte a string data para o tipo de dados DateTime e depois para Float, obtendo a data como um valor Float (3.5) SELECT CAST(CAST(‘1900-01-04 12:00’ AS datetime) AS float) Similar ao CAST. Sintaxe: -- Converte a string data para o tipo de dados DateTime e CONVERT (data_type depois para VarChar de 10 posições, obtendo apenas a [(length)] , expression [style]) parte data no formato dd/mm/yyyy (04/01/1900). SELECT CONVERT(VarChar(10), CAST(‘1900-01-04 12:00’ AS datetime), 103) Existem várias opções de style (opcional), mas os mais utilizados são: 103: Retorna apenas a parte hora no formato dd/mm/yyyy, 108: Retorna apenas a parte hora no formato hh:mm:ss, 114: Retorna apenas a parte hora no formato hh:mi:ss:mmm(24h) * Para ver outros estilos consulte o Books Online do SQL Server. Tabela 3. Funções do SQL Server Caso sua consulta seja utilizada com pouca frequência, você pode realmente fazer uso de algumas dessas funções para simplificar o trabalho com as datas. No entanto, de uma forma geral esta não deve ser considerada uma boa prática. Isso porque embora a utilização de funções permita obter os resultados de forma relativamente simples, quando você usa uma função em uma condição de busca, você acaba matando o índice da tabela caso um índice exista sobre a coluna do tipo data. Ou seja, o SQL Server acaba não usando o índice para otimizar a pesquisa ou acaba fazendo um SCAN no índice. Usando ainda os dados de exemplos da tabela de pedidos (Figura 3), uma opção seria utilizar a função CONVERT para obter todos os registros com Data_Pedido igual a 10-08-2014. M V T e c h | 300 SQL Server: Além do Conceito Blog Post Collection SELECT * FROM TB_PEDIDO WHERE CONVERT(VarChar(10), Data_Pedido, 103) = '10/08/2014' Neste exemplo a função converte o campo Data_Pedido para um VarChar de 10 posições, pegando assim apenas a parte data no formato dd/mm/yyyy e comparando com o valor 10/08/2014. Como resultado, o SELECT retornará os registros 5 e 6, os mesmo retornados na Figura 4. Porém, ao verificar o plano de execução desta consulta (Figura 5) é possível ver claramente que o SQL Server executou um “Index Scan” sobre o índice existente para a coluna Data_Pedido. Figura 5. Index Scan sendo executado sobre o índice da coluna Data_Pedido Observe então na Figura 6 que isso já não acontece quando uma função de conversão não é utilizada. Podemos verificar isso com o script abaixo. SELECT * FROM TB_PEDIDO WHERE Data_Envio >= '2014-08-10' AND Data_Pedido < '2014-08-11' Figura 5. Index Seek sendo executado sobre o índice da coluna Data_Pedido M V T e c h | 301 SQL Server: Além do Conceito Blog Post Collection Um outro exemplo para obter os mesmos resultados seria utilizar as funções MONTH e DAY e YEAR: SELECT * FROM TB_PEDIDO WHERE DAY(Data_Pedido)=10 AND MONTH (Data_Pedido)=08 AND YEAR (Data_Pedido)=2014 Novamente, embora o uso de funções seja uma solução possível, sua utilização deve ser extremamente evitada. Isso porque como vocês devem imaginar a função será chamada para cada registro da tabela, matando então o índice da tabela e gerando um alto consumo dos recursos do servidor. Para uma tabela com milhões de registros, essa prática certamente resultará em possíveis impactos na performance. Minha sugestão é que procurem utilizar a solução com o BETWEEN ou os operadores de comparação >= (maior igual que) e < (menor que) T RABALHANDO COM A PAR TE HORA Realizar uma consulta que busque por uma hora específica é semelhante a realizar uma consulta que busque apenas por uma data (sem a hora). Se a coluna armazenar apenas a parte referente a hora, a busca pela hora será simples. No entanto, diferente dos valores data, o valor referente a hora é representado por um valor numérico aproximado. Podemos ver isso facilmente ao executarmos a seguinte instrução, onde o valor retornado será 0,983321759259259: SELECT CAST(CAST('23:35:59' AS DateTime) AS Float) Para ilustrar a pesquisa apenas pela hora, considerem uma tabela de apontamento de horas com os registros apresentados na Figura 6. Figura 6. Dados de exemplo da tabela de apontamento de horas M V T e c h | 302 SQL Server: Além do Conceito Blog Post Collection O script para criação da tabela e população dos dados de exemplo encontra-se na Listagem 2. Listagem 2. Script para criação e população da tabela de apontamento de horas CREATE TABLE TB_HORA (ID int, Funcionario VarChar(10), Data SmallDateTime, Hora_Entrada DateTime, Hora_Saida DateTime) INSERT VALUES INSERT VALUES INSERT VALUES INSERT VALUES INSERT VALUES INSERT VALUES INTO TB_HORA (1, 'NILTON','2014-10-10','08:30:00','12:30:15') INTO TB_HORA (2, 'NILTON','2014-10-10','13:32:00','17:38') INTO TB_HORA (3, 'CARLOS','2014-10-11','2014-10-11 08:30','12:30') INTO TB_HORA (4, 'CARLOS','2014-10-11','2014-10-11 13:30','17:30') INTO TB_HORA (5, 'CARLOS','2014-10-12','08:30:01.997','12:30') INTO TB_HORA (6, 'CARLOS','2014-10-12','13:30','17:30') Aqui a coluna Hora_Entrada é utilizada de forma inconsistente, ou seja, algumas vezes armazenando somente a hora (a parte data é definida como 1 de Janeiro de 1900), outras vezes armazenando a data e a hora (registros 3 e 4). Com isso, se você utilizar a consulta a seguir para obter apenas os registros com hora de entrada igual a 08:30, você terá como resultado apenas o registro de ID 1: SELECT * FROM TB_HORA WHERE Hora_Entrada = '08:30' O registro de ID 3 não é retornado porque quando se pesquisa apenas pela hora o SQL Server entende que a parte referente à data deve ser 1900-01-01 (zero), o que equivale à data base. Por outro lado, o registro de ID 5 não é retornado porque embora o valor esteja bastante próximo, o mesmo não é 08:30. Com a execução do código a seguir é possível ver como o SQL Server entende esses dois horários em formato numérico: M V T e c h | 303 SQL Server: Além do Conceito Blog Post Collection SELECT CAST(CAST('08:30' AS DateTime) AS Float), CAST(CAST('08:30:01.997' AS DateTime) AS Float) Caso execute o código acima você notará que a hora 08:30 é entendida pelo SQL Server como o valor numérico 0,354166666666667, enquanto que a hora 08:30:01.997 é entendida como 0,354189776234568. Ou seja, realmente são bem diferentes. Nesses casos, para ignorar a parte data de uma coluna DateTime ou SmallDateTime, você pode utilizar a função CONVERT para separar o valor hora de seu componente data: SELECT * FROM TB_HORA WHERE CONVERT (VarChar(5),Hora_Entrada, 108) = '08:30' Conforme apresentado na Figura 7, o SELECT retorna os registros 1, 3 e 5. Figura 7. Resultado do SELECT usando a função de conversão para o campo hora Se a parte hora for armazenada de forma inconsistente, então você também poderá considerar a realização de pesquisas por range de valores hora. A seguinte instrução também retorna os registros 1, 3 e 5: SELECT * FROM TB_HORA WHERE CONVERT (VarChar(5), Hora_Entrada, 108) >= '08:20' AND CONVERT (VarChar(5), Hora_Entrada, 108) <='08:40' Infelizmente, para obter a parte hora não existe uma maneira de obter esse resultado sem usar uma ou mais funções, mas como dito anteriormente, por razões de performance evite a utilização de funções em campos utilizados em busca. Se a parte hora for armazenada de forma consistente, ou seja, sem a parte referente a data, como é o caso da coluna Hora_Saida. Você poderá evitar a utilização de funções fazendo uso de consultas como as M V T e c h | 304 SQL Server: Além do Conceito Blog Post Collection apresentadas abaixo. Mas lembre que neste caso será retornado apenas os registros onde a parte data é 1900-01-01. SELECT * FROM TB_HORA WHERE Hora_Saida BETWEEN '17:30' AND '17:40' SELECT * FROM TB_HORA WHERE Hora_Saida >= '17:30' AND Hora_Saida <='17:40' Nestes exemplos, ambas as consultas retornam os registros 2, 4 e 6. Um outro caminho para trabalhar mais facilmente com valores hora é usar o data type SmallDateTime no lugar do DateTime. Uma vez que o SmallDateTime sempre arredonda a parte hora para o minuto mais próximo (acima ou abaixo), as horas que estiverem entre 08:59:29.999 e 09:00:29.998 serão armazenadas como 09:00. Se esse tipo de arredondamento for possível para sua aplicação, então o uso do SmallDateTime evitará a necessidade de buscas por range de valores hora. CONCLUSÃO Como vimos no decorrer deste artigo, o trabalho com data no SQL Server é relativamente simples quando entendemos como o servidor armazena e trata os valores. Um dos primeiros pontos a saber quando trabalhamos com data é se realmente precisará de uma precisão de milissegundos. Com isso você já decidirá entre o tipo de dados DateTime ou SmallDateTime. Lembre-se que o DateTime ocupa mais espaço (8 bytes) que o SmallDateTime (4 bytes) e quando seu objetivo é tratar apenas a parte hora, pode lhe obrigar a trabalhar com ranges de valores hora. O segundo ponto é sempre garantir a consistência dos valores, ou seja, quando o importante é a parte data tente manter a parte hora sempre como 0, quando o importante for a parte hora, tente manter a parte data sempre como 1 de Janeiro de 1900. Com certeza esses cuidados simplificarão muito seu trabalho com valores data e hora. Um abraço e até a próxima. M V T e c h | 305 SQL Server: Além do Conceito Blog Post Collection Monitorando alterações de Dados com a Cláusula OUTPUT Uma necessidade bastante comum em um ambiente SQL Server está em monitorar as operações DML executadas sobre uma tabela. A partir dpo SQL Server 2008 isso pode facilmente ser alcançado com o uso do CDC (Change Date Capture). No entanto, isso também pode ser facilmente alcançado usando a cláusula OUTPUT. Então, para demonstrar a utilização da cláusula OUTPUT, usaremos como exemplo a tabela CartaoDeCredito que pode ser criada em qualquer banco de dados utilizando o script da Listagem 1. O script cria a tabela e a popula com dois regsitros e em nosso exemplo, esta será a tabela a ser auditada. A auditoria tem como objetivo monitorar os usuários que fizeram alterações nos números dos cartões de crétido. CREATE TABLE dbo.CartaoDeCredito ( [CreditCardID] [int] IDENTITY(1,1) NOT NULL, [CardType] [nvarchar](50) NOT NULL, [CardNumber] [nvarchar](25) NOT NULL, [ExpMonth] [tinyint] NOT NULL, [ExpYear] [smallint] NOT NULL, [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ModifiedDate] DEFAULT (getdate()), CONSTRAINT [PK_CreditCardID] PRIMARY KEY CLUSTERED ([CreditCardID] ASC)) GO INSERT dbo.CartaoDeCredito (CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate) VALUES ('Visa','11111111111111',12,2014,'20090305'), ('MasterCard','22222222222222',12,2020,'20150105') Listagem 1: Script para criação da tabela CartaoDeCredito Conhecendo os objetivos e a estrutura da tabela a ser auditada, é preciso então ter uma segunda tabela que será usada para armazenar os dados da auditoria, chamaremos aqui de "tabela espelho". Uma observação muito importante sobre esta tabela é que para receber as linhas da cláusula OUTPUT ela não pode possuir triggers, check contraints ou qualquer foreign key referenciando suas colunas ou colunas de outras tabelas. Então, com o script apresentado na Listagem 2 é possível criar a tabela que armazenará os dados auditados durante as operações de INSERT, UPDATE e DELETE sobre a tabela CartaoDeCredito. Notem que esta tabela possui duas entradas para cada coluna da tabela a ser auditada. A coluna com o prefixo INSERT armazenará os dados inseridos e a coluna com o prefixo DELETE os dados excluídos. Outro ponto a ser observado são as duas últimas colunas do script (INSERT_Usuario e DELETE_Usuario). Estas colunas existem apenas na tabela espelho e serão utilizadas para guardar a informação referente ao nome do M V T e c h | 306 SQL Server: Além do Conceito Blog Post Collection usuário que modificou o registro na tabela CartaoDeCredito. Para obter esta informação será usada a função de sistema SUSER_SNAME() que retorna o nome do usuário que executou a operação. CREATE TABLE dbo.CartaoDeCredito_Espelho ( AuditoriaID int IDENTITY(1,1) NOT NULL PRIMARY KEY, ComandoDML varchar(10), INSERT_CreditCardID int NULL, DELETE_CreditCardID int NULL, INSERT_CardType [nvarchar](50) NULL, DELETE_CardType [nvarchar](50) NULL, INSERT_CardNumber [nvarchar](25) NULL, DELETE_CardNumber [nvarchar](25) NULL, INSERT_ExpMonth [tinyint] NULL, DELETE_ExpMonth [tinyint] NULL, INSERT_ExpYear [smallint] NULL, DELETE_ExpYear [smallint] NULL, INSERT_ModifiedDate [datetime] NULL, DELETE_ModifiedDate [datetime] NULL, INSERT_Usuario varchar(50) NULL DEFAULT SUSER_SNAME(), DELETE_Usuario varchar(50) NULL DEFAULT SUSER_SNAME() ) Listagem 2: Script para criação da tabela CartaoDeCredito_Espelho Agora que você conhece a estrutura da tabela espelho, com o script da Listagem 3 é possível executar um INSERT sobre a tabela CartaoDeCredito para populá-la com um registro. -- INSERT INSERT dbo.CartaoDeCredito (CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate) -- Início bloco OUTPUT OUTPUT 'INSERT', Inserted.CreditCardID, Inserted.CardType, Inserted.CardNumber, Inserted.ExpMonth, Inserted.ExpYear, Inserted.ModifiedDate INTO dbo.CartaoDeCredito_Espelho (ComandoDML,INSERT_CreditCardID,INSERT_CardType,INSERT_CardNumber ,INSERT_ExpMonth,INSERT_ExpYear,INSERT_ModifiedDate) -- Fim bloco OUTPUT VALUES ('Amex','33333333333333',12,2020,'20150105') Listagem 3: Script para carregar a tabela CartaoDeCredito Note que a cláusula OUTPUT esta posicionada entre as palavras chaves INSERT e VALUES (em negrito na Listagem 3). Em verdade, observando atentamente é possível notar que a instrução de INSERT é muito semelhante a uma instrução de INSERT qualquer, a grande diferença no uso da cláusula OUTPUT está no M V T e c h | 307 SQL Server: Além do Conceito Blog Post Collection fato de ter que acrescentar o código destacado entre os comentários “—Início bloco OUTPUT e –Fim bloco OUTPUT). Tirando este bloco, a instrução de INSERT ficaria como abaixo: INSERT dbo.CartaoDeCredito (CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate) VALUES ('Amex','33333333333333',12,2020,'20150105') Outro ponto importante, notem na Listagem 3 que após o INTO dbo.CartaoDeCredito_Espelho tem-se então a lista das colunas da tabela CartaoDeCredito_Espelho onde os dados devem ser inseridos. Como a operação de INSERT utiliza apenas a tabela virtual INSERTED, a lista de colunas possui apenas as colunas correspondentes. Assim como uma trigger de INSERT, a cláusula OUTPUT também faz uso da tabela virtual INSERTED para obter os dados afetados pela operação DML de INSERT. Quando usamos uma trigger, esta faz uso de duas tabelas chamadas INSERTED e DELETED. Estas tabelas são tabelas virtuais que existem apenas durante o tempo de execução da trigger e podem ser usadas para capturar o antes e depois de uma operação DML. As tabelas são afetadas de forma diferente dependendo da operação DML executada. Na Tabela 1 temos o que contém em cada tabela de acordo com a operação DML. Operação Tabela INSERTED contém Tabela DELETED contém DELETE Não possui registros Registros excluídos INSERT Novos registros Não possui registros UPDATE Novos registros Registros antigos A cláusula OUTPUT faz uso destas mesmas tabelas virtuais, então quando você executa um INSERT a tabela virtual INSERTED possui o dados inseridos na tabela auditada, e a cláusula OUTPUT utiliza a tabela virtual para capturar os dados e inserí-los na tabela CartaoDeCredito_Espelho. O resultado da operação de INSERT executada sobre a tabela CartaoDeCredito com o script da Listagem 3 pode ser visto na Figura 1. Resultado da execução do script abaixo. SELECT TOP 5 * FROM dbo.CartaoDeCredito ORDER BY ModifiedDate DESC GO SELECT ComandoDML,INSERT_CreditCardID,INSERT_CardType,INSERT_CardNumber, INSERT_ExpMonth, INSERT_ExpYear, INSERT_ModifiedDate, INSERT_Usuario FROM dbo.CartaoDeCredito_Espelho M V T e c h | 308 SQL Server: Além do Conceito Blog Post Collection Observe que o novo registro foi inserido sobre a tabela Sales.CartaoDeCredito e ao mesmo tempo um registro também foi inserido sobre a tabela Sales.CartaoDeCredito_Espelho indicando ainda o usuário que executou a operação. Figura 1: Resultado de uma operação de INSERT sobre a tabela CartaoDeCredito Para uma operação de UPDATE, o que muda é que deve-se pegar os dados não apenas da tabela INSERTED, mas também os da tabela DELETED. Isso porque quando ocorre uma operação de UPDATE o que ocorre na prática é a exclusão do dados antigos e a inclusão dos novos dados sendo inseridos. Com isso, durante uma operação de UPDATE a tabela INSERTED armazena os novos dados e a tabela DELETED armazena os dados antigos ou excluídos. Observando o script da Listagem 4 você notará que na lista de colunas passadas para a cláusula OUTPUT é usado não apenas a tabela INSERTED, mas também a DELETED (bloco do OUTPUT). Bem como, após o INTO dbo.CartaoDeCredito_Espelho é informado não apenas as colunas de prefixo INSERT, mas também as de prefixo DELETE. -- UPDATE UPDATE dbo.CartaoDeCredito SET CardNumber= '11111111112015' OUTPUT 'UPDATE', Inserted.CreditCardID, Deleted.CreditCardID, Inserted.CardType, Deleted.CardType, Inserted.CardNumber, Deleted.CardNumber, Inserted.ExpMonth, Deleted.ExpMonth, Inserted.ExpYear, Deleted.ExpYear, Inserted.ModifiedDate, Deleted.ModifiedDate INTO dbo.CartaoDeCredito_Espelho (ComandoDML,INSERT_CreditCardID,DELETE_CreditCardID,INSERT_CardTy pe,DELETE_CardType, INSERT_CardNumber,DELETE_CardNumber,INSERT_ExpMonth,DELETE_ExpMon th,INSERT_ExpYear,DELETE_ExpYear, INSERT_ModifiedDate,DELETE_ModifiedDate) WHERE CreditCardID=3 Listagem 4: Script para executar um UPDATE sobre a tabela CartaoDeCredito M V T e c h | 309 SQL Server: Além do Conceito Blog Post Collection O resultado da operação de UPDATE pode ser visto na Figura 2. Note que na tabela CartaoDeCredito o número do cartão de crédito para o CreditCardID 3 foi alterado de 33333333333333 para 11111111112015. Na tabela de auditoria CartaoDeCredito_Espelho podemos notar que tanto as colunas de prefixo INSERT quanto as colunas de prefixo DELETE foram preenchidas. Na coluna DELETE_CreditCrad temos então o número antes da alteração e na coluna INSERT_CredtCard o novo número do cartão de crédito. O resultado é obtido ao executar o script abaixo: SELECT TOP 5 * FROM dbo.CartaoDeCredito ORDER BY ModifiedDate DESC SELECT ComandoDML,INSERT_CreditCardID,INSERT_CardType, INSERT_CardNumber,INSERT_ExpMonth,INSERT_ExpYear, INSERT_ModifiedDate, INSERT_Usuario FROM dbo.CartaoDeCredito_Espelho SELECT ComandoDML,DELETE_CreditCardID,DELETE_CardType, DELETE_CardNumber,DELETE_ExpMonth,DELETE_ExpYear, DELETE_ModifiedDate, DELETE_Usuario FROM dbo.CartaoDeCredito_Espelho Figura 2: Resultado de uma operação de UPDATE sobre a tabela CartaoDeCredito Para finalizar, um exemplo demonstrando o uso da cláusula OUTPUT em uma operação de DELETE. Como você já deve ter notado, para uma operação de DELETE apenas as colunas com prefixo DELETE para a tabela CartaoDeCredito_Espelho serão preenchidas. O script para a operação de DELETE pode ser visto na Listagem 5 e o exemplo exclui o registro de CreditCardID 3 da tabela dbo.CartaoDeCredito -- DELETE DELETE FROM dbo.CartaoDeCredito OUTPUT 'DELETE', Deleted.CreditCardID, Deleted.CardType, Deleted.CardNumber, Deleted.ExpMonth, Deleted.ExpYear, Deleted.ModifiedDate INTO dbo.CartaoDeCredito_Espelho (ComandoDML,DELETE_CreditCardID,DELETE_CardType, DELETE_CardNumber,DELETE_ExpMonth,DELETE_ExpYear, DELETE_ModifiedDate) WHERE CreditCardID=3 Listagem 5: Script para executar um DELETE sobre a tabela CartaoDeCredito M V T e c h | 310 SQL Server: Além do Conceito Blog Post Collection Podemos ver o resultado da operação na Figura 3. Note que o registro de CreditCardID 3 foi excluído da tabela principal CartaoDeCredito. Para a tabela CartaoDeCredito_Espelho podemos notar também que as colunas de prefixo INSERT estão como NULL e isso ocorre porque para as operações de DELETE não há inserção de novos dados. Já para as colunas de prefixo DELETE, temos o registro dos dados excluídos e quem o excluiu. Figura 3: Resultado de uma operação de DELETE sobre a tabela CartaoDeCredito D ICAS PARA A UTILIZAÇ ÃO DO OUTPUT Como vocês devem ter notado, a cláusula OUTPUT pode ser utilizada nas instruções Transact-SQL de INSERT, UPDATE ou DELETE. Isso proporciona uma excelente flexibilidade, pois podemos utilizá-la apenas nas instruções que desejamos monitorar. Desta forma, qualquer processo que tenha permissão para modificar uma tabela pode usar a cláusula OUTPUT para popular a tabela de auditoria. Algumas boas práticas para a utilização da cláusula OUTPUT são as seguintes: 1) Remover qualquer permissão de acesso direto à tabela auditada; 2) Escrever todas as operações de INSERT, UPDATE e DELETE dentro de stored procedures; 3) Atribuir as permissões apenas nas stored procedures; Seguir estas boas práticas garantirá que o usuário só conseguirá executar as operações através das stored procedures e consequentemente não executará nenhuma operação sem passar pela auditoria. O ponto de atenção ao trabalhar com a cláusula OUTPUT está em ficar sempre atento para não esquecer e fazer as devidas modificações nas procedures quando houver mudanças na estrutura da tabela auditada ou até mesmo não esquecer da cláusula OUTPUT quando estiver escrevendo novas procedures. Para evitar estes problemas, minha sugestão é que sejam criadas regras que definam os passos envolvidos para a modificação ou criação de operações que envolvam tabelas que precisem ser auditadas. É verdade que ao invéz de trabalhar com a cláusula OUTPUT você também poderia executar esta auditoria usando triggers sobre a tabela a ser auditada. No entando, quando trabalhamos com triggers, além de termos os problemas de overhead sobre as tabelas afetas ainda temos que nos preocupar em lembrar das trigger sempre que modificamos as tabelas ou geramos scripts de criação das tabelas. Este problema não existe com a utilização da cláusula OUTPUT pois tudo está dentro das próprias stored procedures que executam as operações de INSERT, UPDATE e DELETE. Se você alterar a tabela auditada, certamente terá que alterar também as procedures que executam estas operações e neste momento verá a cláusula OUTPUT. Se você gerar script de criação das tabelas, muito possivelmente irá gerar também os scripts de criação das stored procedures e mais uma vez estará lá a cláusula OUTPUT. M V T e c h | 311 SQL Server: Além do Conceito Blog Post Collection Abraços Nilton Pinheiro M V T e c h | 312 SQL Server: Além do Conceito Blog Post Collection Tiago Balabuch www.tiagobalabuch.com PERFORMANCE COUNTER - SUBSISTEMA DE DISCOS Os administradores de storages estão constantemente tentando maximizar o desempenho de acesso ao disco e problemas podem ser o resultado de qualquer coisa a partir de um componente configurado incorretamente até um volume de carga extremamente grande. E aqui entra, na minha visão, a “briga” entre o DBA e o Administrator de Storage mas essa é uma história longa. Voltando ao assunto, os bancos de dados estão armazenados em discos (ou pelo menos até a chegada do SQL Server 2014, o recurso de IN-Memory OLT, conhecido também por HEKATON, passa a armazenas dados em memória) que ao contrário da memória RAM, são mídias não-voláteis. U TILIZAÇÃO DE D ISCO A utilização do recurso de disco pode ser medida através de: Operações de I/O por segundo (IOPS) – Número de operações realizadas por segundo Taxa de Transferência (Throughput) – Quantidade de dados (em Megabytes) transferidos O S CONTADORES UTILIZADOS PARA MEDIR AS IN FORMAÇÕES SÃO : Logical Disk: Disk Reads/sec e Disk Write/sec – São respectivamente ao número de operações de leitura e escrita realizadas no volume ou disco. Valores abaixo de 100 IOPS são considerados baixos. Logical Disk: Avg. Disk Read Bytes/Sec e Avg. Disk Write Bytes/Sec – Taxas de transferência para escrita e leitura no subsistema de disco. Valores abaixo de 20MB são considerados baixos. M V T e c h | 313 SQL Server: Além do Conceito Blog Post Collection Gráfico 1 – Total de IOPS O gráfico 1 mostra o consumo de IO do subsistema de disco, onde a utilização máxima chega perto dos 20 mil IOPS. Também é possível notar que a maior concentração na utilização do subsistema de disco para leitura, visto que a gravação de dados consome pouco recurso. Figura 2 – Total de Throughput T EMPO DE R ESPOSTA Podemos definir latência ou tempo de resposta como: uma medida de delay (tempo de atraso) desde o momento de uma requisição de IO é criado, até ao momento em que a requisição de IO é completada. Através de indicadores abaixo é possível dimensionar o impacto da utilização do subsistema de disco. Logical Disk: Avg. Disk sec/Read e Avg. Disk sec/Write – É o tempo médio gasto em leitura e escrita de uma operação de I/O no disco. Esse indicador corresponde ao tempo de resposta do disco, sendo recomendado valores inferiores a 0.020 – equivalente a 20 milissegundos. Logical Disk: Current Disk Queue Lenght – Informa a fila de cada volume ou disco. O valor ideal da fila de disco é zero, porém, existe uma tolerância de até 2 operações de I/O por disco físico. M V T e c h | 314 SQL Server: Além do Conceito Blog Post Collection Gráfico 3 – Tempo de Resposta O gráfico 3 mostra que a fila de disco está alta porém o tempo de resposta do subsistema de disco não ultrapassa 8 milissegundos ou 0.08. Nesse caso o enfileiramento de disco não está atrapalhando o tempo de resposta de IO. REFERÊNCIAS: Windows Performance Monitor Disk Counters Explained http://blogs.technet.com/b/askcore/archive/2012/03/16/windows-performance-monitor-diskcounters-explained.aspx Measuring Disk Latency with Windows Performance Monitor (Perfmon) http://blogs.technet.com/b/askcore/archive/2012/02/07/measuring-disk-latency-with-windowsperformance-monitor-perfmon.aspx M V T e c h | 315 SQL Server: Além do Conceito Blog Post Collection PROBLEMAS DE REDE – ASYNC_NETWORK_IO Há um tempo atrás, fiz uma análise em conjunto com um amigo, Rafael Carneiro Machado, de problemas com lentidão em um site. O Rafael trabalha comigo, porém no time de Web e ajudou a identificar o problema que estávamos tendo, assim como a escrever o texto abaixo. O BJETIVO Diagnosticar e identificar as possíveis causas de lentidão em um site que estavam ocorrendo. O diagnóstico iniciou-se de forma geral nos ambientes de Web e Banco de Dados e os contadores de performance foram sendo refinados de acordo com as evidências encontradas. Depois da análise realizada, foram identificadas evidências de um problema na rede que interliga os ambientes de Web e Banco de Dados. Dessa maneira nossos esforços foram direcionados para tanto. Incidente Reportado: Lentidão e timeout em alguns momentos do acesso ao site A NÁLISE I NICIAL – B ANCO DE D ADOS : Foi realizada uma análise em cima da instância de banco de dados, que hospedava o site e foi identificado um alto tempo de espera do tipo ASYNC_NETWORK_IO, quase 15%. Porque esse valor é alto? Em particular, nunca tinha visto esse tipo de espera com um valor alto e isto me chamou a atenção, pois sempre vi um valor próximo a 0% ou no máximo a 2%. Aqui foi o ponto que levou a nossa investigação a se concentrar que poderia existir um problema relacionado à rede, mas o que era exatamente nesse momento ainda não sabíamos. Figura 1 Esse tipo de espera indica que o SQL Server está respondendo para a aplicação, porém a mesma não está conseguindo processar no tempo correto. M V T e c h | 316 SQL Server: Além do Conceito Blog Post Collection Figura 2 Algumas ações que podemos tomar para tentar identificar a causa raiz do problema: Identificar results sets grandes e verificar com a equipe de sistema se isso realmente está de acordo com o negócio. Se nem todas as linhas do result set serão necessárias, devemos alterar o código para restringir essa quantidade de linhas. Devemos verificar as configurações de placa de rede e verificar se não existe nenhum problema. Validar os componentes de rede entre a aplicação/cliente e a instancia do SQL Server A NÁLISE I NICIAL – WEB: Não foi identificado nenhum time-out no ambiente Web, o que tínhamos era a demora do Banco de Dados em responder as requisições dos servidores de aplicação. Isso pode ser identificado pela quantidade de conexões com o estado “SYN_SENT”, porém esta informação apenas indica que a primeira ação do ThreeWay-Handshake foi iniciada, onde a origem informou ao destino que deseja iniciar uma comunicação. Normalmente não vemos este estado de conexão, pois as comunicações de SYN, SYN-ACK e ACK ocorrem quase de forma instantânea exceto em casos como este, onde o servidor de destino demora a enviar a resposta do SYN à origem, porém não existia registro de time-out. Monitoramos os pacotes entre os servidores de aplicação e banco de dados e pudemos ver que o servidor de banco de dados estava demorando para enviar a resposta, mas respondia a requisição dos servidores de aplicação: M V T e c h | 317 SQL Server: Além do Conceito Blog Post Collection Figura 3 Nesse momento, suspeitávamos que o problema pudesse estar ocorrendo por falta de portas TCP para realizar a comunicação devido a um alto trafego de dados. Foi realizado um monitoramento e a média de conexões TCP em portas distintas em cada servidor era de 800, independente do destino. Se levarmos em conta que por padrão a quantidade de portas dinâmicas no Windows 2008 é de 16384 portas (49152 a 65535), ainda sobram mais de 15 mil portas livres: Figura 4 Figura 5 O que poderia estar acontecendo era uma limitação nas portas dinâmicas dos servidores de banco. Essa nossa suspeita não se confirmou, pois dificilmente o problema estava na falta de “portas altas” nos servidores de aplicação. Outro detalhe importante que não poderíamos deixar de lado, era que o tráfego entre Web e Banco de Dados passava por um appliance de balanceamento, um intrusion prevention system (IPS), Firewall e outros equipamentos de rede física. A NÁLISE DETALHADA Após análise inicial, foi constatada a possibilidade de um problema de rede, a partir desse ponto uma nova investigação foi realizada com foco neste quesito utilizando as ferramentas de análise de performance do próprio sistema operacional, o Perfmon. O S CONTADORES UTILIZADOS FORAM : Network Interface % Network Utilization M V T e c h | 318 SQL Server: Além do Conceito Blog Post Collection Output Queue Length % Network Utilization Sent % Network Utilization Received Packets Outbound Errors Bytes Total/sec Current Bandwidth Packets/secPackets Sent/sec Packets Received/sec Packets Received Unknown Packets Received Discarded Packets Outbound Discarded Packets Sent Unicast/sec Processor % DPC Time DPCs Queued/sec TCPv4 Connection Failures Segments/sec Connections Established Connections Reset Segments Received/sec Connections Passive Connections Active Segments Retransmitted/sec Segments Sent/sec AMBIENTE DE BANCO DE DADOS M V T e c h | 319 SQL Server: Além do Conceito Blog Post Collection Figura 6 Os itens que mais se destacaram foram a quantidade de pacotes recebidos descartados e com erro, além disso, o número de segmentos TCP retransmitidos e de conexões com falha também estão altos. Figura 7 M V T e c h | 320 SQL Server: Além do Conceito Blog Post Collection Figura 8 A figura 8 mostra os segmentos TCP que precisaram ser retransmitidos por algum erro de rede. Outro ponto de destaque é a quantidade de conexões TCP com falha. O fabricante recomenda que este contador não ultrapasse o número de 10 conexões TCP com falha por hora. No ambiente de banco de dados este valor está com uma média de 20. As figuras 9 e 10 mostram esse comportamento. Figura 9 M V T e c h | 321 SQL Server: Além do Conceito Blog Post Collection Figura 10 AMBIENTE WEB Figura 11 No ambiente Web não tínhamos qualquer indício na camada física de erros, porém o mesmo problema identificado no ambiente de Banco de Dados ocorre no ambiente Web. Esse problema trata-se da camada de transporte, várias conexões com falha e retransmitidas. M V T e c h | 322 SQL Server: Além do Conceito Blog Post Collection Figura 12 O padrão de segmentos retransmitidos se repete no ambiente Web, consequência das conexões TCP com falhas. Figura 13 Esse comportamento no ambiente web foi detectado em todos os servidores da farm. R ESOLUÇÃO Esse comportamento foi enviado para equipe de rede, que realizou as ações necessárias na camada física dos equipamentos fazendo assim com que o trafego de pacotes ocorresse com sucesso. O site em questão apresentou uma melhora significante, onde seu carregamento inicial passou de 14 segundos para apenas 2,8 segundos. CONCLUSÃO Por algum motivo relacionado a rede, o Banco de Dados estava com muitos pacotes com erros e descartados e isso gerava a necessidade de retransmissão dos mesmos, ocasionando demora na entrega M V T e c h | 323 SQL Server: Além do Conceito Blog Post Collection das informações que a aplicação demandava. O resultado final era a lentidão no acesso e carregamento do site. Foi constatado que até mesmo para iniciar a comunicação entre Web e Banco de Dados o problema ocorria. O servidor Web enviava o pacote de SYN, o qual o servidor de banco de dados recebia o pacote e enviava o ACK. Este pacote de ACK estava sendo corrompido em algum ponto e a aplicação informava ao banco de dados que ainda não havia recebido sua confirmação (ACK), fazendo com que o Banco de Dados tentasse enviá-lo novamente. Este período entre tentativas e falhas até que o ACK seja enviado corretamente e a comunicação estabelecida, é um exemplo de como a retransmissão de pacotes TCP pode impactar na performance do site. Essa retransmissão não ocorre apenas durante o processo de “Three Way Handshake”, mas também quando a comunicação já está estabelecida e efetivamente os dados estão sendo enviados do banco de dados para os servidores de aplicação. REFERÊNCIAS: http://msdn.microsoft.com/pt-br/library/ms179984.aspx http://en.wikipedia.org/wiki/Handshaking http://support.microsoft.com/kb/929851/en-us http://msdn.microsoft.com/pt-br/library/ms179984.aspx M V T e c h | 324 SQL Server: Além do Conceito Blog Post Collection Suspect database - MSDTC in-doubt transaction Em uma bela madrugada, onde todas as coisas obscuras aparecem, um dos servidores de um cluster falhou e executou um failover para um outro nó. Até esse momento nada de estranho e esse é o comportamento esperado. PROBLEMA Ao verificar os bancos de dados da instancia que sofreu o failover me deparei com o status de “suspect” em um deles. Nesse ponto começou a investigação de como isso aconteceu e como resolver! CONSEGUI ENCONTRAR NO ERRORLOG AS SEGUINTES MENSAGENS: Attempting to initialize Microsoft Distributed Transaction Coordinator (MS DTC). This is an informational message only. No user action is required. QueryInterface failed for “DTC_GET_TRANSACTION_MANAGER_EX::ITransactionDispenser”: 0x80004005(failed to retrieve text for this error. Reason: 15105). QueryInterface failed for “ITransactionDispenser”: 0x80004005(failed to retrieve text for this error. Reason: 15105). Attempting to initialize Microsoft Distributed Transaction Coordinator (MS DTC). This is an informational message only. No user action is required. SQL Server detected a DTC/KTM in-doubt transaction with UOW {07372A47-24B9-4BC3-A6510260624FFF8E}. Please resolve it following the guideline for Troubleshooting DTC Transactions. An error occurred while recovering database ‘XXX’. Unable to connect to Microsoft Distributed Transaction Coordinator (MS DTC) to check the completion status of transaction (0:-222014414). Fix MS DTC, and run recovery again. An error occurred during recovery, preventing the database ‘XXX’ (database ID 5) from restarting. Diagnose the recovery errors and fix them, or restore from a known good backup. If errors are not corrected or expected, contact Technical Support. A aplicação que utilizava essa database também utilizava Microsoft Distributed Transaction Coordinator (MSDTC) e tudo indicava que alguma coisa se perdeu no caminho da comunicação entre o MSDTC da aplicação e do banco de dados. No meu caso eu tinha um agravante: o cluster não possuía uma instância do MSDTC, ou seja, utilizava o MSDTC local. M V T e c h | 325 SQL Server: Além do Conceito Blog Post Collection Quando uma instância do SQL Server 2008 ou superior é inicializada em um cluster, ela tenta encontrar uma instância do MSDTC para comunicação na seguinte ordem: Dentro do grupo do cluster onde reside o recurso do SQL Server Dentro de outros grupos do cluster Instância MSDTC local RESOLUÇÃO Eu não sabia o que tinha acontecido com MSDTC e resolvi tomar uma ação para deixar meu banco de dados online e depois tentar resolver qualquer problema. Utilizei o comando abaixo: sp_configure ‘show advanced options’, 1 go reconfigure go sp_configure ‘in-doubt xact resolution’, 2 go reconfigure go sp_configure ‘show advanced options’, 0 go reconfigure go E depois trouxe o banco de dados ONLINE. Podem existir outras formas de resolver esse problema, porém essa ação permitiu que meu banco de dados ficasse online e pude executar um DBCC CHECKDB que para meu alivio retornou sem nenhum erro! Antes de liberar meu banco de dados para produção novamente voltei a configuração padrão M V T e c h | 326 SQL Server: Além do Conceito Blog Post Collection sp_configure ‘in-doubt xact resolution’, 0 go reconfigure go Outra alterativa seria visualizar a view sys.dm_tran_active_transactions, essa view mostra algumas informações sobre as transações com uso do MSDTC. Os campos: transaction_uow, transaction_state, dtc_state são campos que devem ser olhados com cuidado em uma análise pois contem informações importantes. Assim você pode identificar o status da sua transação e pode tomar a ação necessária que cabe ao seu ambiente. CONCLUSÃO Quando a instância SQL Server executou um failover para o outro nó do cluster, a instância passou a se comunicar com o MSDTC local do novo nó, que não tinha informações das transações registradas no nó anterior. Ao tentar iniciar o processo de recovery do banco de dados, o SQL Server encontrou informações sobre transações distribuídas que não haviam sido terminadas (confirmadas ou abortadas) antes da falha. O SQL Server entrou no processo de validar as informações do LOG e questionou o MSDTC a respeito das transações, e o novo MSDTC local não tinha informações a respeito destas transações. Por esse motivo o SQL Server não foi capaz de resolve-las e desta forma interrompeu o processo de recovery ocasionando o estado de “suspect” A melhor solução para que isso não ocorra é ter uma instancia do MSDTC dentro do cluster. M V T e c h | 327 SQL Server: Além do Conceito Blog Post Collection R EFERÊNCIAS : How to configure DTC for SQL Server in a Windows 2008 cluster Opção de configuração de servidor in-doubt xact resolution sys.dm_tran_active_transactions M V T e c h | 328 SQL Server: Além do Conceito Blog Post Collection Felipe Ferreira www.templar.com.br/blogs/Felipe A carreira de DBA está morrendo? Com a popularidade da nuvem crescendo a cada dia uma das perguntas que eu recebo frequentemente é: “a carreira de DBA está morrendo? O que você vai fazer da vida no futuro?” Neste artigo eu irei dar a minha opinião pessoal sobre o futuro da nossa amada profissão e tentar acalmar aqueles que já começaram a procurar uma nova carreira. A primeira coisa que eu gostaria de falar é que quando a gente começou a trabalhar com TI nós sabíamos que esta era uma carreira diferente de muitas outras. Uma carreira dinâmica e empolgante que se reinventa o tempo todo, com novidades tecnológicas aparecendo todos os anos e mudando todo o panorama da área. Nós escolhemos uma profissão que nos obriga a continuar estudando, aprendendo e evoluindo. E esse é o pensamento que eu gostaria que vocês leem este artigo. O papel do Administrador de Banco de Dados não está desaparecendo, nós não somos uma espécime ameaçada de extinção e não entraremos nesta lista em um futuro próximo. A nuvem não é a nossa inimiga. O mercado de dados está apenas evoluindo e a nuvem está trazendo diversas novidades que irão nos dar mais poder, mais opções. N O MERCADO DE HOJE NÓS TEMOS DOIS PROBLEM AS MUITO COMUNS : 1. As empresas não conseguem encontrar profissionais suficiente Todos sabemos disso. Eu tenho certeza que todos conhecem diversas empresas que tem vagas em aberto a diversos meses, já entrevistaram dezenas de pessoas e simplesmente não conseguem encontrar ninguém adequado para a vaga. 2. As empresas querem manter os seus custos o mais baixo possível As empresas querem ter lucro e nós acabamos de sair de uma grande crise mundial. Isso significa que as empresas estão constantemente tentando encontrar formas de melhorar a sua produtividade e manter os seus custos o mais baixo possível. Em um cenário como esse as ferramentas que a nuvem nos fornece servem tanto para melhorar nossa produtividade como DBA e também para ajudar a empresa a economizar dinheiro. Vamos pensar um pouco, quantas tarefas a gente realiza diariamente que não trazem nenhum valor real para o negócio? Sem dúvida que quando estamos planejando uma nova solução de alta disponibilidade ou realizando performance tuning naquela consulta lenta nós podemos ver o valor que isso irá trazer para a empresa. M V T e c h | 329 SQL Server: Além do Conceito Blog Post Collection No primeiro caso, irá garantir que todas as aplicações estejam de pé e rodando quando a empresa precisa e o segundo irá ajudar com que o servidor aguente a carga de trabalho, execute mais sessões simultaneamente e fazer com que nossos clientes internos e externos fiquem mais felizes. Mas e aquele tempo que você perdeu tentando encontrar mais espaço em disco para os seus bancos de dados? Tentando encontrar espaço em disco para armazenar os backups porque o banco de dados cresceu mais do que o previsto. E o tempo que você gasta instalando atualizações no Windows e no SQL? Em algumas grandes empresas nós temos times de administradores de storage e infra-estrutura que irão se preocupar com essas tarefas que usei como exemplo, mas essa não é a realidade de todo mundo. A grande maioria de pequenas e médias empresas possui apenas um pequeno time que é responsável por múltiplas áreas. E porque isso? Volte alguns parágrafos acima nos itens 1 e 2 da minha lista que você irá entender. Eu espero você ler. Agora vamos tentar imaginar uma outra realidade. Vamos imaginar um mundo onde eu recebo um alerta de falta de disco para armazenar os meus backups. A nossa empresa adquiriu a pouco tempo uma outra empresa, o que fez com que o crescimento dos bancos fosse muito maior do que o previsto originalmente e nós ficamos sem espaço em disco. Então ao invés de esperar dias/meses por um processo de compra de mais discos eu vou até um portal Web e alguns cliques do mouse depois eu tenho 1TB extra de disco disponível. Tudo que preciso fazer agora é abrir o SQL Management Studio e alterar os meus Jobs de backup para utilizar a nova área de disco. Problema resolvido em menos de 15 minutos. Vamos imaginar um mundo onde eu possa pegar todos aqueles banco de dados pequenos que eu tenho, bancos que não são muito importantes para o negócio (sim, nós todos temos vários desses bancos, não tente mentir para você mesmo) e agora vamos mover esses bancos para a nuvem para economizar recursos do servidor local para as bases mais críticas. Quem sabe eu consiga até diminuir o número de servidores necessários localmente assim eu não preciso me preocupar com licenças, suporte, aplicar patches naquela máquina. Isso não seria ótimo? E que tal se livrar completamente dos ambientes de homologação e testes e substituir eles por máquinas virtuais na nuvem que eu posso simplesmente desligar quando não estiverem em uso, economizando dinheiro para a empresa? E aquelas tabelas enormes, que contem milhões de registros e nos causam problemas todos os dias, não seria ótimo substituir aquela solução complexa de particionamento que nós desenvolvemos para gerenciar dados históricos ou pouco acessados e ao invés disso permitir que o SQL Server gerencie automaticamente esses dados, movendo os registros antigos para a nuvem, enquanto mantem os dados acessíveis para o cliente de forma transparente? A nuvem realmente é algo que vai mudar a carreira de muitos, mas não algo que irá matar o papel do administrador do banco de dados e destruir famílias. Mas ao invés disso, é algo que irá nos tornar mais eficientes, que irá nos fornecer ferramentas e opções que permitam que a gente nos foque em tarefas que irão trazer realmente valor para a empresa, utilizar de forma mais eficiente o hardware existente, para tornar nossas vidas mais fáceis. Então abrace as mudanças, da mesma forma que abraçamos todas as outras novas tecnologias que vieram antes dela e use cada tecnologia como uma ferramenta para te ajudar a ter sucesso no seu trabalho. M V T e c h | 330 SQL Server: Além do Conceito Blog Post Collection Criando um datawarehouse para testes Para fazer testes com bases de diferentes tamanhos eu utilizo o datawarehouse dos testes da TPC. Rapidamente, para quem não conhece, a Transaction Processing Performance Council, ou TPC para os íntimos (não pergunte o que aconteceu com o outro P), é a organização que define alguns benchmarks que todos os fabricantes utilizam para fazer testes de performance, com isso ela mantem a lista das configurações de Hardware + Software com a melhor performance, o melhor custo x benefício e assim por diante. Para os meus testes eu utilizo o TPC-H, que é um teste de Decision Support, ou seja, utiliza uma base no formato datawarehouse, e não a base OLTP. Se você deseja fazer esse teste com uma base OLTP acredito que possa usar o mesmo procedimento com o teste TPC-E, apesar de nunca ter procurado. Temos N formas de criar as bases de dados da TPC-H, irei partir para a mais manual de todas por nos dar maior liberdade para fazer N testes. Então mãos na massa. Toda a estrutura da base de dados e tabelas está na documentação oficial do bechmarch TPC-H, que vocês podem encontrar no endereço http://www.tpc.org/tpch/spec/tpch2.14.0.pdf. Mas vamos facilitar as coisas. P ASSO 1: - Criar nossa base de dados. Aqui eu não vou colocar nada de dicas, melhores práticas de como criar, quais opções habilitar e desabilitar na base de dados, porque isso vai ficar de lição de casa para vocês, testar carregar os dados com diversas opções e ver a diferença de tempo entre uma forma e outra. Irei fazer outros posts fazendo essas comparações futuramente. Então vamos apenas criar nossa base com os 2 filegroups que precisaremos para os próximos passos, o filegroup LOAD_FG será nosso filegroup de Staging, muita gente cria uma base de dados separada para ser a área de Staging, nesse caso, estamos criando na mesma base de dados em um filegroup separado; o filegroup DATA_FG é o filegroup com os dados já tratados, nosso datawarehouse final. 1: CREATE DATABASE TPCH 2: ON PRIMARY 3: ( NAME = tpch1g_root, 4: FILENAME = "D:\TPC\tpch1g.mdf", 5: SIZE = 10MB, 6: FILEGROWTH = 10MB), 7: FILEGROUP DATA_FG 8: (name=tpch1g_data1,filename='D:\TPC\tpch1g.ndf',size=2048mb,fileg rowth=1024Mb), 9: 10: FILEGROUP LOAD_FG 11: (name=tpch1g_load1, filename='D:\TPC\load1g.ndf',size=2048mb,filegrowth=1024mb) M V T e c h | 331 SQL Server: Além do Conceito Blog Post Collection 12: 13: LOG ON 14: (name=tpch1g_log, filename='C:\TPC\tpch1G.ldf',size=1024mb) Obs.: Lembre-se da dica do post anterior do Instant File Initialization para criar grandes bases de dados e realizar as cargas: http://www.templar.com.br/blogs/felipe/2013/02/24/instant-file-initialization/ P ASSO 2: - Criar nossas tabelas no Filegroup LOAD_FG, o nosso filegroup de staging. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: USE TPCH GO create table PART (P_PARTKEY P_NAME P_MFGR P_BRAND P_TYPE P_SIZE P_CONTAINER P_RETAILPRICE P_COMMENT on LOAD_FG int varchar(55) char(25) char(10) varchar(25) int char(10) float varchar(23) not null, not null, not null, not null, not null, not null, not null, not null, not null) create table SUPPLIER (S_SUPPKEY S_NAME S_ADDRESS S_NATIONKEY S_PHONE S_ACCTBAL S_COMMENT on LOAD_FG int char(25) varchar(40) int char(15) float varchar(101) not null, not null, not null, not null, not null, not null, not null) create table PARTSUPP (PS_PARTKEY PS_SUPPKEY PS_AVAILQTY PS_SUPPLYCOST PS_COMMENT on LOAD_FG int int int float varchar(199) not null, not null, not null, not null, not null) create table CUSTOMER (C_CUSTKEY C_NAME C_ADDRESS C_NATIONKEY int varchar(25) varchar(40) int M V T e c h | 332 not not not not null, null, null, null, SQL Server: Além do Conceito Blog Post Collection 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: C_PHONE C_ACCTBAL C_MKTSEGMENT C_COMMENT on LOAD_FG char(15) float char(10) varchar(117) not null, not null, not null, not null) create table ORDERS (O_ORDERKEY O_CUSTKEY O_ORDERSTATUS O_TOTALPRICE O_ORDERDATE O_ORDERPRIORITY O_CLERK O_SHIPPRIORITY O_COMMENT on LOAD_FG bigint int char(1) float date char(15) char(15) int varchar(79) not null, not null, not null, not null, not null, not null, not null, not null, not null) create table LINEITEM (L_ORDERKEY L_PARTKEY L_SUPPKEY L_LINENUMBER L_QUANTITY L_EXTENDEDPRICE L_DISCOUNT L_TAX L_RETURNFLAG L_LINESTATUS L_SHIPDATE L_COMMITDATE L_RECEIPTDATE L_SHIPINSTRUCT L_SHIPMODE L_COMMENT on LOAD_FG bigint int int int float float float float char(1) char(1) date date date char(25) char(10) varchar(44) not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null, not null) create table NATION (N_NATIONKEY N_NAME N_REGIONKEY N_COMMENT on LOAD_FG int char(25) int varchar(152) not null, not null, not null, not null) create table REGION (R_REGIONKEY R_NAME R_COMMENT on LOAD_FG int char(25) varchar(152) not null, not null, not null) P ASSO 3: M V T e c h | 333 SQL Server: Além do Conceito Blog Post Collection Feito isso já temos nossa base de dados e as tabelas no nosso filegroup de staging, agora precisamos dos dados para carregar nessas tabelas. Para isso vamos usar o DBGen, a ferramenta fornecida pela TPC para gerar os arquivos de dados. A TPC fornece esse aplicativo como uma solução do Visual Studio em C++, você pode fazer o download do código fonte aqui, como sei que nem todos os DBA’s possuem o Visual Studio completo instalado, então vou disponibilizar os executáveis já compilados aqui no blog, você pode baixar o aplicativo compilado aqui. Para utilizar é só descompactar (ou compilar caso você tenha baixado o código fonte), abrir um prompt de comando, navegar até a pasta com o código compilado e executar: dbgen –vf –s 1 Sendo o –s 1, a quantidade de GB que você deseja gerar, no exemplo, serão criados arquivos para popular todas as tabelas acima, totalizando 1Gb em tamanho. Para criar uma base de 10Gb, 50Gb, 100Gb você só precisa alterar o valor no parâmetro Os outros dois parametros, –vf é verbose para mostrar todos os passos na tela e o f de force para sobreescrever arquivos existentes no disco. Digite dbgen –? para ver todas as opções. P ASSO 4: Carregar os dados! Aqui temos N opções, e é aqui que a brincadeira começa.. se você quiser pode simplesmente usar um BULK INSERT e carregar direto os dados para as tabelas do filegroup LOAD_FG e depois criar pacotes do SSIS ou scripts T-SQL para mover os dados para o filegroup Data_FG, pode criar pacotes do Integration Services para carregar tudo, pode usar o BCP, enfim.. pode usar toda a criativade que Odin lhe deu… para ajudar as pessoas que só querem fazer as consultas, testar desempenho, tentar criar um columnstore index, etc, aqui vai a sintaxe do comando BULK INSERT: 1: bulk insert (FieldTerminator = 2: bulk insert (FieldTerminator = 3: bulk insert (FieldTerminator = 4: bulk insert (FieldTerminator = 5: bulk insert (FieldTerminator = 6: bulk insert (FieldTerminator = 7: bulk insert (FieldTerminator = REGION from 'C:\tpc\Region.tbl' with '|', RowTerminator ='|\n',tablock) CUSTOMER from 'C:\tpc\Customer.tbl' with '|', RowTerminator ='|\n',tablock) NATION from 'C:\tpc\nation.tbl' with '|', RowTerminator ='|\n',tablock) PART from 'C:\tpc\part.tbl' with '|', RowTerminator ='|\n',tablock) SUPPLIER from 'C:\tpc\SUPPLIER.tbl' with '|', RowTerminator ='|\n',tablock) PARTSUPP from 'C:\tpc\partsupp.tbl' with '|', RowTerminator ='|\n',tablock) ORDERS from 'C:\tpc\orders.tbl' with '|', RowTerminator ='|\n',tablock) M V T e c h | 334 SQL Server: Além do Conceito Blog Post Collection 8: bulk insert LINEITEM from 'C:\tpc\LINEITEM.tbl' with (FieldTerminator = '|', RowTerminator ='|\n',tablock) E é isso pessoal, no arquivo compilado acima eu também adicionei o QGEN que gera 22 consultas pesadas para vocês testarem os servidores. Só digite na linha de comando QGEN.exe > consultas.sql que ele irá gerar a consulta, ou abra os arquivos .SQL que estão na pasta e editem os filtros/etc. Nos próximos posts vou usar essa base de dados para realizar testes de carga e comparações de desempenho. M V T e c h | 335