<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Thiago Caserta</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/tcaserta/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/tcaserta/feed.xml</link>
    <description>A SQL PFE looking to share some knowledge, although he himself is still learning</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:27:12 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>SQL em 5 Minutos [Episódio # 2]: Wait Statistics - LOGBUFFER</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/sql-em-5-minutos-episdio-2-wait-statistics-logbuffer</link>
      <pubDate>Tue, 09 Feb 2016 08:53:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2016/02/09/sql-em-5-minutos-episdio-2-wait-statistics-logbuffer/</guid>
      <description><![CDATA[Fala galera!
Gostaria de anunciar que o epis&oacute;dio 2 da s&eacute;rie SQL em 5 minutos...]]></description>
      <content:encoded><![CDATA[<p>Fala galera!</p>
<p>Gostaria de anunciar que o epis&oacute;dio 2 da s&eacute;rie SQL em 5 minutos j&aacute; est&aacute; no ar!&nbsp;<br />Nesse epis&oacute;dio, dou continuidade ao primeiro assunto que estou abordando na s&eacute;rie: Wait Statistics, com foco em um segundo Wait Type, o LOGBUFFER.&nbsp;</p>
<p>Voc&ecirc; pode assistir o v&iacute;deo atrav&eacute;s do link: [View:https://youtu.be/1S0K14M0oIc]&nbsp;</p>
<p>Se voc&ecirc; curtir, compartilhe com sua rede de contatos e amigos que voc&ecirc; acha que iriam se beneficiar do conte&uacute;do e se inscreva no meu canal para ter acesso aos v&iacute;deos assim que forem publicados!</p>
<p>Como mencionei no post anterior sobre essa s&eacute;rie, todos os feedbacks s&atilde;o bem vindos e eu gostaria que&nbsp;enviassem suas d&uacute;vidas sobre SQL Server, pois no futuro quero dedicar alguns v&iacute;deos dessa s&eacute;rie para responder perguntas sobre o produto, funcionalidades, bem como outros aspectos que achem interessantes.</p>
<p>Espero que gostem!</p>
<p>Um abra&ccedil;o,</p>
<p>Thiago Caserta.</p>]]></content:encoded>
    </item>
    <item>
      <title>Comportamento "estranho" utilizando Identity - intevalo nos valores da sequência após restart</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/comportamento-estranho-utilizando-identity-intevalo-nos-valores-da-sequncia-aps-restart</link>
      <pubDate>Mon, 25 Jan 2016 11:00:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2016/01/25/comportamento-estranho-utilizando-identity-intevalo-nos-valores-da-sequncia-aps-restart/</guid>
      <description><![CDATA[Nos &uacute;ltimos meses tenho trabalhado, dentro de um dos meus clientes, mais pr&oacute;ximo do...]]></description>
      <content:encoded><![CDATA[<p>Nos &uacute;ltimos meses tenho trabalhado, dentro de um dos meus clientes, mais pr&oacute;ximo do time de DBAs que s&atilde;o mais focados na administra&ccedil;&atilde;o f&iacute;sica dos ambientes e, talvez por isso, n&atilde;o tenho recebido muitas perguntas dos desevolvedores que trabalham nessa mesma empresa.</p>
<p>H&aacute; algumas semanas, por&eacute;m, um desenvolvedor me trouxe uma situa&ccedil;&atilde;o interessante que eu n&atilde;o consegui explicar o motivo logo de cara. Talvez porque, como eu mencionei, h&aacute; alguns meses tenho focado menos em desenvolvimento, ou talvez porque a grande maioria das tabelas que gerenciamos hoje em dia possuem bem mais do que 1000 registros.</p>
<p>O cliente me encaminhou o seguinte report do <em>Connect</em> e disse que ap&oacute;s um Failover uma das tabelas com uma coluna identity saltou de 63 para 1001.</p>
<p>&nbsp;<a href="https://connect.microsoft.com/SQLServer/feedback/details/739013/failover-or-restart-results-in-reseed-of-identity">https://connect.microsoft.com/SQLServer/feedback/details/739013/failover-or-restart-results-in-reseed-of-identity</a></p>
<p>Ele j&aacute; me apontou de cara um Trace Flag, o 272, pois disse ter pesquisado o assunto e que com esse Trace Flag esse comportamento n&atilde;o acontecia. Ao mesmo tempo ele achou estranho e disse suspeitar de um <em>bug</em> no produto.</p>
<p>Bem, mais interessado do que no TF em si, j&aacute; que se h&aacute; um Trace Flag eu j&aacute; entendo que se trata de uma altera&ccedil;&atilde;o do comportamento padr&atilde;o, eu queria entender o porque esse comportamento deveria ser ent&atilde;o esperado.</p>
<p>&nbsp;A primeira coisa, e talvez a mais &oacute;bvia, que eu fiz, foi ler a documenta&ccedil;&atilde;o sobre o Identity, e vi algo que me chamou a aten&ccedil;&atilde;o e at&eacute; ent&atilde;o eu realmente desconhecia.</p>
<p>&nbsp;&ldquo;Consecutive values after server restart or other failures &ndash; SQL Server might cache identity values for performance reasons and some of the assigned values can be lost during a database failure or server restart. This can result in gaps in the identity value upon insert. If gaps are not acceptable then the application should use its own mechanism to generate key values. Using a sequence generator with the NOCACHE option can limit the gaps to transactions that are never committed.&rdquo;</p>
<p><a href="https://technet.microsoft.com/en-in/library/ms186775.aspx">https://technet.microsoft.com/en-in/library/ms186775.aspx</a></p>
<p>Aqui j&aacute; percebi uma coisa sobre o caso que ele me trouxe: N&atilde;o, isso n&atilde;o &eacute; um <em>bug</em>, como ele havia sugerido inicialmente, e sim um comportamento esperado, apenas confirmando minhas suspeitas. Ao mesmo tempo isso talvez seja considerado um comportamente bem estranho para alguns.&nbsp;</p>
<p>Relendo a documenta&ccedil;&atilde;o do SQL 2008 R2 por exemplo, h&aacute; apenas um alerta com rela&ccedil;&atilde;o a poss&iacute;veis <em>gaps</em> na sequ&ecirc;ncia do identity, sempre causados por dele&ccedil;&atilde;o de registros, algo esperado, mas n&atilde;o por uma falha, ou at&eacute; mesmo um simples restart&nbsp; como nesse cen&aacute;rio.</p>
<p>&nbsp;Testando o comportamento, percebi que ele, de fato, acontece. Veja que interessante essa sequ&ecirc;ncia ap&oacute;s o restart da minha inst&acirc;ncia 2012.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/71/76/8168.pic.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-71-76/8168.pic.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/71/76/8168.pic.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/70x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-71-76/8168.pic.png" alt="" border="0" /></a></p>
<p>A pergunta agora &eacute;: Em que situa&ccedil;&atilde;o esse comportamento, at&eacute; ent&atilde;o um pouco bizarro, faz sentido? Bem, seguindo a documenta&ccedil;&atilde;o do SQL 2012, aqui est&aacute;, talvez, a principal raz&atilde;o:</p>
<p>"SQL Server might cache identity values for <span style="text-decoration: underline;"><strong>performance reasons</strong></span> and some of the assigned values can be lost during a database failure or server restart ... These restrictions are <strong><span style="text-decoration: underline;">part of the design in order to improve performance</span></strong>.".</p>
<p>Analisando mais a fundo, a minha explica&ccedil;&atilde;o final &eacute; de que a partir da vers&atilde;o 2012 o SQL Server utiliza um cache de 1000 entradas para colunas identity. Ou seja, h&aacute; 1000 valores reservados que j&aacute; est&atilde;o em mem&oacute;ria, ou seja, em cache, para que o desempenho seja superior em caso de novas escritas. Caso n&atilde;o seja utilizado todos os valores dentro daquele cache, no caso de um restart por exemplo, a sequ&ecirc;ncia &eacute; reiniciada, por&eacute;m como se trata de um cache de 1000 registros, n&atilde;o seria poss&iacute;vel reinciciar o mesmo a partir do valor 0, j&aacute; que existem registros inseridos, ent&atilde;o ele reinicia, automaticamente, a partir do primeiro valor do pr&oacute;ximo intervalo, de 1001 a 2000, por exemplo.</p>
<p>Existem dois "workarounds" para esse comportamento, que mais uma vez, &eacute; assim <em>by design</em>:&nbsp;</p>
<ol>
<li>Habilitar a TF272, como mencionei no come&ccedil;o, nos par&acirc;metros de inicializa&ccedil;&atilde;o da inst&acirc;ncia</li>
<li>Utilizar o SEQUENCE, introduzido no SQL 2012, para tabelas que cont&eacute;m menos de 1000 registros</li>
</ol>
<p><strong>Qual o impacto de se utilizar o TF272?</strong></p>
<p>Considerando que o cache de 1000 valores para colunas identity&nbsp;tem o objetivo de aumentar o desempenho durante a inser&ccedil;&atilde;o de novos registros, habilitar o TF anula essa otimiza&ccedil;&atilde;o do produto. Pra ser sincero, testando e simulando o desempenho das minhas escritas, eu n&atilde;o senti muita diferen&ccedil;a, por&eacute;m se voc&ecirc; considerar milhares de inser&ccedil;&otilde;es por minuto, talvez o comportamento padr&atilde;o seja, de fato, ben&eacute;fico.</p>
<p>Um abra&ccedil;o,</p>
<p>Thiago Caserta.</p>]]></content:encoded>
    </item>
    <item>
      <title>Nova Série: SQL em 5 Minutos [Episódio # 1]: Wait Statistics - ASYNC_NETWORK_IO</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/nova-srie-sql-em-5-minutos-episdio-1-wait-statistics-async_network_io</link>
      <pubDate>Sat, 23 Jan 2016 08:34:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2016/01/23/nova-srie-sql-em-5-minutos-episdio-1-wait-statistics-async_network_io/</guid>
      <description><![CDATA[Enquanto estou finalizando o meu primeiro video da s&eacute;rie SQL Fundamentos, a qual meu amigo...]]></description>
      <content:encoded><![CDATA[<p>Enquanto estou finalizando o meu primeiro video da s&eacute;rie SQL Fundamentos, a qual meu amigo Fabricio Catae iniciou, eu resolvi criar uma nova s&eacute;rie, que vai focar em aspectos importantes do dia a dia de qualquer profissional que trabalhe com a Plataforma de Dados da Microsoft.</p>
<p>A id&eacute;ia &eacute; complementar o conte&uacute;do da s&eacute;rie Fundamentos e lhe ajudar a se munir de informa&ccedil;&otilde;es para resolver problemas em seus ambientes SQL&nbsp;da melhor forma poss&iacute;vel (mais r&aacute;pido e mais assertivo).</p>
<p>O primeiro video da s&eacute;rie, que chama SQL em 5 minutos, porque quero fazer diversos v&iacute;deos curtos, que geralmente s&atilde;o mais f&aacute;ceis de digerir e n&atilde;o tomam muito do seu tempo, tem na verdade 13 minutos. Hahaha. O motivo &eacute; simples. Eu dei uma breve introdu&ccedil;&atilde;o &agrave; s&eacute;rie e ao t&oacute;pico que iremos abordar nos primeiros v&iacute;deos da s&eacute;rie.</p>
<p>[View:https://www.youtube.com/watch?v=lAsR5EolYdA]&nbsp;</p>
<p>Feedbacks s&atilde;o bem vindos e eu gostaria que&nbsp;enviassem suas d&uacute;vidas sobre SQL Server, pois no futuro quero dedicar alguns v&iacute;deos dessa s&eacute;rie para responder perguntas sobre o produto, funcionalidades, bem como outros aspectos.</p>
<p>Espero que gostem!</p>
<p>&nbsp;</p>
<p>Um abra&ccedil;o,</p>
<p>Thiago Caserta.</p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server Fundamentos: Storage Engine (Parte I)</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/sql-server-fundamentos-storage-engine-parte-i</link>
      <pubDate>Mon, 04 Jan 2016 12:00:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2016/01/04/sql-server-fundamentos-storage-engine-parte-i/</guid>
      <description><![CDATA[Eu estou finalizando a grava&ccedil;&atilde;o de um v&iacute;deo para a s&eacute;rie SQL Server...]]></description>
      <content:encoded><![CDATA[<p>Eu estou finalizando a grava&ccedil;&atilde;o de um v&iacute;deo para a s&eacute;rie SQL Server Fundamentos, projeto iniciado pelo meu amigo e mentor t&eacute;cnico Fabricio Catae no Channel 9.<br />Vou focar este primeiro v&iacute;deo em um dos componentes que eu mais gosto de falar, o Storage Engine. Como o v&iacute;deo ainda est&aacute; em fase de produ&ccedil;&atilde;o, resolvi transcrever o conte&uacute;do deste v&iacute;deo em formato de post aqui no meu blog.</p>
<p>Infelizmente n&atilde;o poderia cobrir todos os aspectos do Storage Engine em um v&iacute;deo de 15 minutos, por isso acredito que teremos mais v&iacute;deos falando especificamente deste componente. Espero que gostem.&nbsp;</p>
<p><strong>STORAGE ENGINE </strong></p>
<p>O Storage Engine &eacute; um dos componentes mais complexos do SQL Server. Ele &eacute; o principal componente, junto a Engine Relacional, dentro do SQL Server. Apesar de o Storage Engine e o Relational Engine serem totalmente independentes, eles interagem entre si atrav&eacute;s dos components de acesso nativo, como o OLE DB.</p>
<p>As principais responsabilidades do Storage Engine s&atilde;o:</p>
<ul>
<li>Gerenciar o armazenamento dos dados em discos e todo o IO necess&aacute;rio para acesso a essa estrutura</li>
<li>Armazenar e gerenciar as estruturas f&iacute;sicas dos objetos, utilizando blocos, como p&aacute;ginas</li>
<li>Prover a capacidade de manter dados em uma estrutura de mem&oacute;ria, chamada de buffer, ou cache</li>
<li>Controlar concorr&ecirc;ncia</li>
<li>Gerenciar transa&ccedil;&otilde;es e locks</li>
<li>Recuperar os dados em caso de falhas</li>
</ul>
<p>Vamos falar um pouco sobre alguns dos itens mencionados.&nbsp;</p>
<p><br /> <strong>ARMAZENAMENTO</strong><br /> <br /> Assim como outras plataformas relacionais, o SQL Server possui uma estrutura de mem&oacute;ria, parte do Storage Engine, conhecida como Buffer Pool, ou Buffer Cache. Essa estrutura armazena p&aacute;ginas de mem&oacute;ria de 8k, o tamanho utilizado, por padr&atilde;o no SQL Server, para armazenamento dos dados.</p>
<p>As p&aacute;ginas de 8k s&atilde;o armazenadas fisicamente nos arquivos de dados, os .mdf e .ndf, em grupos de 8 p&aacute;ginas. Essa estrutura de 8 p&aacute;ginas de 8k chama-se extents, o que forma uma estrutura com tamanho total de 64k. O SQL Server utiliza a estrutura de extents para otimizar as leituras e escritas por ler e escrever mais dados ao inv&eacute;s de apenas 8k, por&eacute;m algumas opera&ccedil;&otilde;es fazem especificamente IOs de 8k, por lidarem com p&aacute;ginas espec&iacute;ficas.</p>
<p>Vamos dar um pouco mais de foco agora em como ocorre a intera&ccedil;&atilde;o do Buffer Pool com os demais componentes e demais tarefas do SQL quando uma leitura &eacute; realizada.</p>
<p><strong>PROCESSO DE LEITURA DOS DADOS</strong></p>
<p>Quando efetuamos uma leitura a partir da nossa aplica&ccedil;&atilde;o, por exemplo, uma dll C#, h&aacute; um fluxo natural a ser seguido.</p>
<p>Sua aplica&ccedil;&atilde;o se conecta ao SQL Server atrav&eacute;s da camada de Protocolos e sua consulta deve obrigatoriamente passar pela Engine Relacional. O Relational Engine ent&atilde;o faz a valida&ccedil;&atilde;o, ou Parse da Query, e durante o processo de otimiza&ccedil;&atilde;o gera um Plano de Execu&ccedil;&atilde;o para esta consulta. Este plano ent&atilde;o &eacute; armazenado numa &aacute;rea de mem&oacute;ria, conhecida como Plan Cache para otimizar as pr&oacute;ximas execu&ccedil;&otilde;es desta query. N&atilde;o vou entrar em muitos detalhes sobre o otimizador de queries ou plan cache nesse momento, mas falaremos mais sobre isso quando entrarmos em Relational Engine.</p>
<p>Este plano de execu&ccedil;&atilde;o gerado pela Engine Relacional serve como um mapa para que o pr&oacute;ximo componente, o Storage Engine, seja capaz de buscar os dados solicitados da melhor forma poss&iacute;vel, ou quase isso, j&aacute; que durante a otimiza&ccedil;&atilde;o, o otimizador de queries n&atilde;o escolhe necessariamente o melhor plano mas sim um plano bom o suciente para a execu&ccedil;&atilde;o da Query. A Raz&atilde;o &eacute; simples, demandaria muito tempo escolher o melhor plano poss&iacute;vel.</p>
<p>A partir deste plano o Storage Engine pode realizar as tarefas necess&aacute;rias para buscar os dados que suas consultas solicitaram. O primeiro local no qual o Storage Engine tenta buscar os seus dados &eacute; no seu pr&oacute;prio cache, ou seja, o Buffer Pool. Todas as consultas passam obrigatoriamente por essa &aacute;rea de mem&oacute;ria. Caso as p&aacute;ginas de dados que possuem os dados que voc&ecirc; precisa estejam em mem&oacute;ria (nesta &aacute;rea de cache), a sua consulta pode ser retornada com sucesso. Sem a necessidade de ler seus arquivos f&iacute;sicos, esse tipo de leitura, em mem&oacute;ria, &eacute; muito mais r&aacute;pida, &eacute; o que chamamos de leitura l&oacute;gica ou logical read.</p>
<p>Caso os dados que voc&ecirc; est&aacute; buscando n&atilde;o estejam no Buffer Pool, o Storage Engine &eacute; respons&aacute;vel por iniciar e gerenciar a leitura em disco, nos arquivos de dados, buscando pela informa&ccedil;&atilde;o que voc&ecirc; est&aacute; procurando, obviamente levando em conta o plano de execu&ccedil;&atilde;o, ou o mapa, por assim dizer, que foi passado para ele pela Engine Relacional. Nesse momento, ap&oacute;s o IO em disco ser efetuado, o Storage Engine armazena as p&aacute;ginas lidas no Buffer Pool para que possa otimizar as pr&oacute;ximas leituras que solicitarem as mesmas p&aacute;ginas.</p>
<p>N&oacute;s chamamos esse processo de leitura em disco de Leitura F&iacute;sica dos dados, j&aacute; que o SQL precisou realizar IO em disco para efetivamente encontrar os seus dados.</p>
<p>Uma vez os dados em mem&oacute;ria, ou seja, nessa &aacute;rea de Cache, o Buffer Pool, o SQL Server n&atilde;o precisa mais realizar uma leitura F&iuml;sical e, nesse caso, ele realiza, apenas, a Leitura L&oacute;gica, j&aacute; mencionada</p>
<p><strong>LAZY WRITER</strong></p>
<p>Obviamente, o Buffer Pool, ou essa &aacute;rea de mem&oacute;ria que comporta as p&aacute;ginas dos seus bancos de dados &eacute; limitada. Vamos imaginar que essa &aacute;rea de mem&oacute;ria em um determinado servidor tenha a capacidade de armazenar 4GB e voc&ecirc; j&aacute; est&aacute; utilizando efetivamente um total de 3.8GB. O que aconteceria se uma nova leitura de 400Mb ocorresse?</p>
<p>Nesse caso, o SQLOS, o sistema operacional do SQL Server, atrav&eacute;s de um dos seus componentes internos, chamado Resource Monitor, veria que uma press&atilde;o interna de mem&oacute;ria est&aacute; ocorrendo, afinal, 200Mb n&atilde;o s&atilde;o suficientes para acomodar os 400Mb. Ele ent&atilde;o enviaria uma notifica&ccedil;&atilde;o para que esse pequeno problema de mem&oacute;ria no Buffer Pool seja tratado por um agente de gerenciamento de recurso, ou uma tarefa interna. Esse &ldquo;agente&rdquo; ou tarefa interna, respons&aacute;vel por gerenciar a mem&oacute;ria do Buffer Pool &eacute; chamado de Lazy Writer. O Lazy Write ent&atilde;o acordaria, e limparia do cache p&aacute;ginas sujas, ou seja, p&aacute;ginas que j&aacute; foram modificadas e j&aacute; est&atilde;o salvas em disco, nos seus arquivos de dados.</p>
<p>Essa tarefa &eacute; um pouco diferente do CHECKPOINT.</p>
<p>O CHECKPOINT &eacute; uma tarefa respons&aacute;vel por escrever p&aacute;ginas que foram modificadas no Buffer Pool para os arquivos de dados, por&eacute;m o CHECKPOINT n&atilde;o necessariamente remove essas p&aacute;ginas dessa &aacute;rea de cache, ou seja, a quantidade de dados em mem&oacute;ria n&atilde;o diminui ap&oacute;s a execu&ccedil;&atilde;o de um CHECKPOINT. Vamos falar um pouco mais sobre CHECKPOINT quando detalharmos o processo de escrita.</p>
<p>J&aacute; o Lazy Writer &eacute; respons&aacute;vel pela limpeza dessa &aacute;rea de cache, utilizando um algoritimo chamado LRU2 (Least Recently Used), ou seja, as p&aacute;ginas mais antigas, ou as que foram utilizadas menos recentemente, s&atilde;o marcadas como dispon&iacute;veis para serem reutilizadas por outras aloca&ccedil;&otilde;es.</p>
<p>No meu exemplo ent&atilde;o, apesar de eu j&aacute; ter 200Mb dispon&iacute;veis, outros 200Mb ser&atilde;o disponibilizados em forma de p&aacute;ginas marcadas como dispon&iacute;veis, j&aacute; que elas foram limpas do meu Buffer Pool pelo Lazy Writer.<br /> <br /> Essas p&aacute;ginas deixam de existir em mem&oacute;ria, por&eacute;m ainda est&atilde;o em disco, uma vez que o SQL deve garantir a persist&ecirc;ncia dos dados.</p>
<p>Se uma nova leitura &eacute; realizada e busca por dados que est&atilde;o nessas p&aacute;ginas que acabaram de ser removidas do Buffer Pool, ele n&atilde;o executa apenas leituras l&oacute;gicas, como faria anteriormente quando minhas p&aacute;ginas ainda existiam em mem&oacute;ria, mas tamb&eacute;m leitura f&iacute;sica nos arquivos de dados em que essas p&aacute;ginas se encontram.<br />&nbsp;</p>
<p><strong>CONCLUS&Atilde;O</strong></p>
<p>Nesse primeiro v&iacute;deo vou falar um pouco mais sobre um dos componentes do SQL Server: O Storage Engine. Este componente possui muitos outros aspectos a serem analisados. <br />No pr&oacute;ximo v&iacute;deo vou analisar um pouco mais a fundo o processo de escrita e como o Storage Engine desempenha um papel importante para garantir a consist&ecirc;ncia e durabilidade dos dados.</p>]]></content:encoded>
    </item>
    <item>
      <title>Distribuição de dados no SQL Server e o algoritmo Proportional Fill</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/distribuio-de-dados-no-sql-server-e-o-algoritmo-proportional-fill</link>
      <pubDate>Mon, 19 Oct 2015 10:54:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/10/19/distribuio-de-dados-no-sql-server-e-o-algoritmo-proportional-fill/</guid>
      <description><![CDATA[H&aacute; algumas semanas eu tive a oportunidade de palestrar no Webcast do Grupo SQL Maniacs, do...]]></description>
      <content:encoded><![CDATA[<p>H&aacute; algumas semanas eu tive a oportunidade de palestrar no Webcast do Grupo SQL Maniacs, do meu amigo Vitor Fava.</p>
<p>Nessa oportunidade falei sobre um tema muito interessante, por&eacute;m pouco falado em eventos e at&eacute; mesmo em posts t&eacute;cnicos: A Distribui&ccedil;&atilde;o de dados no SQL Server.</p>
<p>Se voc&ecirc; tem interesse em entender como isso funciona na pr&aacute;tica, convido voc&ecirc; a assistir esse webcast no link:&nbsp;<a href="https://www.youtube.com/watch?v=XXbVLzfKwsQ">https://www.youtube.com/watch?v=XXbVLzfKwsQ</a></p>
<p>L&aacute;, inclusive, voc&ecirc; pode ver uma DEMO que cobre alguns pontos que vou destacar neste post.</p>
<p>Vou tentar resumir um pouco o que falei nessa ocasi&atilde;o.</p>
<p>Como todos os profissionais que trabalham com o SQL Server e outros bancos de dados relacionais sabem, uma das responsabilidades do sistema gerenciador de banco de dados (SGDB) &eacute; manter e gerenciar os dados em mem&oacute;ria. Por&eacute;m, apesar desses dados serem utilizados em mem&oacute;ria, os mesmos devem persistir em disco, o que garante alguns dos atributos que todos os bancos de dados relacionais devem respeitar, entre eles a Durabilidade. O SQL Server basicamente usa dois tipos de arquivo para este prop&oacute;sito, o arquivo de Transaction Log, que possui a extens&atilde;o .ldf, e o arquivos de dados, que possuem a extens&atilde;o .mdf, para o arquivo prim&aacute;rio, e .ndf para os arquivos que foram criados posteriormente, ou seja, os arquivos secund&aacute;rios. Nesse primeiro momento n&atilde;o vou me atentar ao arquivo de log, j&aacute; que ele possui uma estrutura bem diferente dos arquivos de dados e &eacute; utilizado para outros prop&oacute;sitos, como a recoverabilidade dos dados em caso de falhas e por algumas features. Vamos focar aqui nos arquivos de dados, os .mdf e .ndf.</p>
<p>No SQL Server, algo que faz parte da arquitetura de arquivos &eacute; o que chamamos de Filegroup (FG), ou Grupo de arquivos. Ele basicamente &eacute; utilizado para agrupar os arquivos de forma "l&oacute;gica". Do ponto de vista f&iacute;sico n&atilde;o h&aacute; nenhuma mudan&ccedil;a, por&eacute;m o Filegroup &eacute; utilizado para aloca&ccedil;&atilde;o dos dados e administra&ccedil;&atilde;o dos arquivos.</p>
<p>Quando criamos um objeto, por exemplo uma tabela, n&atilde;o podemos simplesmente especificar em qual arquivo f&iacute;sico (.mdf ou .ndf) esta tabela ser&aacute; armazenada, por&eacute;m podemos definir em qual Filegroup ela residir&aacute;, no momento da cria&ccedil;&atilde;o da mesma, como voc&ecirc; pode ver na imagem abaixo.&nbsp;Uma vez em determinado Filegroup esta tabela poderia alocar dados em qualquer dos arquivos que fazem parte deste mesmo FG.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/71/76/7558.filegroup.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-71-76/7558.filegroup.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/71/76/7558.filegroup.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-71-76/7558.filegroup.png" alt="" border="0" /></a>&nbsp;</p>
<p>Se voc&ecirc; trabalha com SQL Server, voc&ecirc; j&aacute; percebeu que um Filegroup &eacute; automaticamente gerado durante a cria&ccedil;&atilde;o de um banco de dados. Este &eacute; o Filegroup prim&aacute;rio e o arquivo de dados prim&aacute;rio (.mdf) &eacute; o &uacute;nico arquivo pertencente a este FG inicialmente. Neste arquivo at&eacute; ent&atilde;o n&atilde;o h&aacute; dados de usu&aacute;rio e &eacute; por isso que muitos DBAs, como uma boa pr&aacute;tica, as vezes criam um novo filegroup e novos arquivos de dados alocados neste novo FG para a aloca&ccedil;&atilde;o de dados de usu&aacute;rio. Dessa forma seu FG prim&aacute;rio estaria sendo utilizado apenas para armazenar dados de sistema.&nbsp;</p>
<p>Infelizmente n&atilde;o tive tempo de explicar, durante o webcast, como a aloca&ccedil;&atilde;o de dados funciona de forma detalhada, e na verdade pretendo fazer um post espec&iacute;fico para falar sobre esse assunto, mas para resumir, podemos dizer que o SQL Server utiliza mapas de aloca&ccedil;&atilde;o para alocar dados, dessa forma o SQL pode encontrar de forma "r&aacute;pida" quais extents/p&aacute;ginas est&atilde;o dispon&iacute;veis para novas aloca&ccedil;&otilde;es e o percentual de espa&ccedil;o dispon&iacute;vel nessas p&aacute;ginas. Mas como eu disse, vamos falar sobre GAM, SGAM, PFS e IAM em uma pr&oacute;xima oportunidade.</p>
<p>Cada arquivo de dados possui suas pr&oacute;prias p&aacute;ginas de sistema e mapas de aloca&ccedil;&atilde;o. Por exemplo: O arquivo1.ndf possui mapas de aloca&ccedil;&atilde;o distintos do arquivo2.ndf, se ambos os arquivos pertencem ao mesmo Filegroup o SQL Server pode distribuir os dados do objeto que foi criado neste filegroup entre esses dois arquivos e ter como benef&iacute;cio o fato de ter mais mapas de aloca&ccedil;&atilde;o sendo utilizados paralelamente. Num banco de dados de usu&aacute;rio &eacute; muito raro ver problemas de desempenho causados por conten&ccedil;&atilde;o nessas p&aacute;ginas de sistema, j&aacute; que a aloca&ccedil;&atilde;o de novos objetos n&atilde;o &eacute; t&atilde;o constante a ponto de causar isso. Por outro lado, um banco de dados que conhecemos muito bem, o tempdb, &eacute; utilizado n&atilde;o s&oacute; quando criamos novos objetos tempor&aacute;rios, mas durante outras opera&ccedil;&otilde;es, por isso n&atilde;o &eacute; raro casos em que por se ter apenas um arquivo de dados (.mdf) para o tempdb, essa conten&ccedil;&atilde;o, por causa do acesso frequente a esses mapas de aloca&ccedil;&atilde;o, comece a gerar problemas de performance. Esse &eacute; um dos principais motivos para a recomenda&ccedil;&atilde;o de se criar mais arquivos de dados para o banco de dados tempdb, para evitar essa poss&iacute;vel conten&ccedil;&atilde;o dos mapas de aloca&ccedil;&atilde;o.&nbsp;</p>
<p>Bem, voltando aos bancos de dados de usu&aacute;rio. Vamos usar um objeto como exemplo, para falar um pouco mais sobre a distribui&ccedil;&atilde;o dos dados.&nbsp;<br /> <br /> Imagine que voc&ecirc; criou a Tabela1.</p>
<p>Quando o SQL Server vai fazer aloca&ccedil;&atilde;o de dados nesta tabela, se a mesmo foi criada em um Filegroup em que h&aacute; mais de um arquivo, os dados podem ser distribu&iacute;dos entre eles.</p>
<p>Como ent&atilde;o o SQL Server decide a quantidade de dados que ser&aacute; alocada em cada arquivo? Aqui entre em cena um algor&iacute;tmo que &eacute; respons&aacute;vel por fazer essa distribui&ccedil;&atilde;o: O Proportional Fill.</p>
<p>O Proportional Fill &eacute; utilizado para que todos os arquivos que perten&ccedil;am a um mesmo filegroup cheguem ao seu limite, ou seja, termine o seu espa&ccedil;o dispon&iacute;vel, "aproximadamente", ao mesmo tempo. &Eacute; aproximadamente mesmo, porque dependendo da diferen&ccedil;a de espa&ccedil;o dispon&iacute;vel entre os arquivos, obviamente pode ser que um dos arquivos encha primeiro. A quest&atilde;o aqui &eacute; que se a distribui&ccedil;&atilde;o &eacute; Proporcional, isso significa que o SQL Server ir&aacute; distribuir os dados baseados em alguma m&eacute;trica.&nbsp;<br /> <br /> Qual &eacute; esta m&eacute;trica? &Eacute; algo bem simples e l&oacute;gico, na verdade: O percentual de espa&ccedil;o dispon&iacute;vel em cada arquivo.</p>
<p>Para ficar mais f&aacute;cil de entender, vamos imaginar o seguinte cen&aacute;rio.</p>
<p>Voc&ecirc; tem a Tabela1 alocada no Filegroup1. O Filegroup1 possui os arquivos: arquivo1.ndf, arquivo2.ndf, arquivo3.ndf e arquivo4.ndf.</p>
<p>Se os arquivos possuem um percentual diferente de espa&ccedil;o dispon&iacute;vel entre eles, a distribui&ccedil;&atilde;o proporcional ir&aacute; fazer com que mais dados sejam alocados no arquivo com mais espa&ccedil;o dispon&iacute;vel. Obviamente, isso n&atilde;o significa que os outros arquivos n&atilde;o ir&atilde;o "receber" dados, mas eles ir&atilde;o receber proporcionalmente menos aloca&ccedil;&otilde;es.</p>
<p>Aqui est&aacute; a quantidade de espa&ccedil;o dispon&iacute;vel em cada arquivo:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="312">
<p align="center"><strong>Arquivo de Dados</strong></p>
</td>
<td width="312">
<p align="center"><strong>Espa&ccedil;o Dispon&iacute;vel</strong></p>
</td>
</tr>
<tr>
<td width="312">
<p align="center">Arquivo1.ndf</p>
</td>
<td width="312">
<p align="center">100 Mb</p>
</td>
</tr>
<tr>
<td width="312">
<p align="center">Arquivo2.ndf</p>
</td>
<td width="312">
<p align="center">200 Mb</p>
</td>
</tr>
<tr>
<td width="312">
<p align="center">Arquivo3.ndf</p>
</td>
<td width="312">
<p align="center">50 Mb</p>
</td>
</tr>
<tr>
<td width="312">
<p align="center">Arquivo4.ndf</p>
</td>
<td width="312">
<p align="center">400 Mb</p>
</td>
</tr>
</tbody>
</table>
<p>Nesse cen&aacute;rio, o SQL Server faria um c&aacute;culo para determinar a propor&ccedil;&atilde;o em que os dados devem ser distribu&iacute;dos. Seria algo mais ou menos assim:</p>
<p>A soma do espa&ccedil;o dispon&iacute;vel significa 100% do espa&ccedil;o.&nbsp;<br /> Ou Seja: 100Mb + 200Mb + 50Mb + 400Mb = 750Mb.</p>
<p>750Mb = 100%.</p>
<p>Quanto cada arquivo representa sobre o total de espa&ccedil;o dispon&iacute;vel?</p>
<p>Utilizando o arquivo1.ndf como exemplo:</p>
<p>Arquivo1.ndf = 100Mb.&nbsp;<br /> (100/750)*100 = 13-14%.</p>
<p>Ou seja, o arquivo1.ndf deveria receber em torno de 14% dos novos dados alocados, assim como o Arquivo2.ndf receberia em torno de 26%, Arquivo3.ndf 6% e o Arquivo4.ndf 54%, j&aacute; que ele &eacute; o arquivo com mais espa&ccedil;o dispon&iacute;vel.</p>
<p>&Eacute; claro que esses n&uacute;meros come&ccedil;am a sofrer mudan&ccedil;as conforme as aloca&ccedil;&otilde;es forem feitas e, isso diretamente afeta o percentual de dados alocados em cada arquivo. Mas a id&eacute;ia &eacute; que o SQL Server distribua os dados de forma proporcional para garantir aquilo que mencionei no in&iacute;cio da explica&ccedil;&atilde;o sobre o Proportional Fill: Que todos os arquivos cheguem ao seu fim, &ldquo;aproximadamente&rdquo; ao mesmo tempo.</p>
<p>Agora que voc&ecirc; entendeu como funciona o Proportional Fill, a pergunta &eacute;: H&aacute; vantagens em se ter aloca&ccedil;&otilde;es distribu&iacute;das entre diversos arquivo? Sem d&uacute;vida, primeiramente estamos otimizando a utiliza&ccedil;&atilde;o dos arquivos do ponto de vista de espa&ccedil;o dispon&iacute;vel e, apesar de esses dados serem proporcionalmente distribu&iacute;dos, eu estaria quebrando as aloca&ccedil;&otilde;es entre diversos arquivos. Se cada um deles estiver em um disco diferente, isso poderia at&eacute; gerar uma certa medida de performance.&nbsp;<br /> <br /> &Oacute;timo! Mas voc&ecirc; n&atilde;o concorda que se eu conseguir fazer uma distribui&ccedil;&atilde;o mais equitativa, ou seja, uma distribui&ccedil;&atilde;o por igual entre os arquivos, eu n&atilde;o teria um desempenho ainda melhor?&nbsp;<br /> Bem, se todos os arquivos estiverem no mesmo disco, pra ser sincero, tanto faz, j&aacute; que estaria compartilhando spindles ou seja, a mesma capacidade/velocidade de leitura/escrita do disco entre todos os arquivos. E lembre-se, apesar de eu ter mais mapas de aloca&ccedil;&atilde;o que podem ser utilizados em paralelo, bancos de usu&aacute;rio raramente apresentam problemas de conten&ccedil;&atilde;o nessas p&aacute;ginas.</p>
<p>Agora, imagine cada um desses arquivos em um disco separado, ou melhor, o que realmente importa, eu tenha spindles diferentes pra cada arquivo. Sem d&uacute;vida os ganhos de desempenho poderiam ser bem interessantes. <br />Qual ent&atilde;o seria a resposta para garantir uma distribui&ccedil;&atilde;o equitativa?</p>
<p>Eu sei o que voc&ecirc; pensou e, est&aacute; correto! Garantir que todos os arquivos de dados deste filegroup possuam o mesmo percentual de espa&ccedil;o dispon&iacute;vel.</p>
<p>Para isso eu preciso, primeiro, durante a cria&ccedil;&atilde;o do banco de dados, garantir o mesmo tamanho inicial dos meus arquivos de dados. Segundo, que as&nbsp; configura&ccedil;&otilde;es de Autogrowth, ou seja, de auto-crescimento, de todos os arquivos pertencentes &agrave;quele filegroup sejam id&ecirc;nticas.&nbsp;<br /><br /> O que? Um PFE falando sobre auto-crescimento? Ok ok, eu sei que voc&ecirc; est&aacute; pensando: &ldquo;Bem, mas n&atilde;o acho que eu deveria habilitar a op&ccedil;&atilde;o de autogrowth, j&aacute; que isso &eacute; um processo custoso. O SQL tem que preencher o espa&ccedil;o alocado no disco com zeros (0) e isso poderia afetar minhas transa&ccedil;&otilde;es durante esse per&iacute;odo&rdquo;. Isso &eacute; verdade, apesar de podermos otimizar este processo utilizando o instant file initialization que, por exemplo, poderia reduzir o tempo de aloca&ccedil;&atilde;o de &ldquo;lixo&rdquo; no espa&ccedil;o alocado em disco, uma boa pr&aacute;tica &eacute; realizar crescimentos dos seus bancos de dados de forma manual em um hor&aacute;rio mais conveniente. Por&eacute;m, n&oacute;s sabemos que h&aacute; empresas que simplesmente n&atilde;o conseguem fazer isso. Se seu footprint, ou seja, a quantidade de ambientes SQL que voc&ecirc;&nbsp; administra &eacute; grande, voc&ecirc; simplesmente vai optar pelo auto-crescimento e aqui sim minha recomenda&ccedil;&atilde;o &eacute; utilizar op&ccedil;&otilde;es que podem transformar essa tarefa em algo mais otimizado (ou menos custoso), como configurar o crescimento em Mb ao inv&eacute;s de % e ter o Instant File Initialization habilitado (aqui vai mais um assunto pra outro post).</p>
<p>A quest&atilde;o &eacute;, garantindo que as configura&ccedil;&otilde;es de auto-crescimento sejam id&ecirc;nticas entre seus arquivos, nos d&aacute; a certeza de que seus arquivos sempre ter&atilde;o o mesmo percentual de espa&ccedil;o dispon&iacute;vel entre eles, e isso garante com que a distribui&ccedil;&atilde;o dos dados para seus objetos sejam equitativa.</p>
<p>No exemplo que eu utilizei anteriormente, se os 4 aquivos possuissem 200Mb de espa&ccedil;o dispon&iacute;vel, o SQL Server simplesmente distribuiria 25% do total de dados alocados em cada um dos arquivos. Coloque cada um desses arquivos em um disco diferente, sim, voc&ecirc; teria mais desempenho.&nbsp;<br /> <br /> H&aacute; apenas um &uacute;nico detalhe a ser destacado com rela&ccedil;&atilde;o autogrowth. O evento de auto-crescimento em si &eacute; round-robin.&nbsp;<br /> Como assim Thiago? Isso mesmo. Se voc&ecirc; encheu seus arquivos - aqui um detalhe importante, o auto-grow s&oacute; ocorre ap&oacute;s TODOS os arquivos daquele determinado FIlegroup terem chegado ao seu limite - o evento de auto-crescimento, por padr&atilde;o, n&atilde;o ocorre simultaneamente em todos os arquivos. O SQL Server "aleatoriamente" escolhe um dos arquivos pertencentes a aquele Filegroup e dispara o evento de auto-crescimento. A partir da&iacute; voc&ecirc; passa a utilizar apenas um dos arquivos para TODAS as aloca&ccedil;&otilde;es, j&aacute; que os outros arquivos possuem 0% de espa&ccedil;o dispon&iacute;vel. Este arquivo que cresceu chegou ao seu limite? O SQL Server dispara o auto-crescimento para o pr&oacute;ximo arquivo, e assim por diante, at&eacute; que todos os arquivos j&aacute; tenham crescido e a&iacute;, esse ciclo se repete. Isso n&atilde;o &eacute; um problema, este &eacute; um comportamente esperado e &eacute; assim que o algoritmo funciona.</p>
<p>Ou seja, baseado no que vimos at&eacute; agora, &nbsp;voc&ecirc; pode at&eacute; tirar algumas vantagens em se ter uma distribui&ccedil;&atilde;o equitativa entre v&aacute;rios arquivos, por&eacute;m, quando TODOS os arquivos &nbsp;de um determinado Filegroup chegam ao seu limite, por causa do evento de auto-crescimento utilizar um algoritmo round-robin, voc&ecirc; pode simplesmente deixar de ver esse comportamento de distribui&ccedil;&atilde;o das aloca&ccedil;&otilde;es em v&aacute;rios arquivos.</p>
<p>&Eacute; claro que cada caso &eacute; um caso, talvez no seu cen&aacute;rio voc&ecirc; nem queira fazer uso do Proportional Fill para distribuir seus dados entre diversos arquivos. Mas, vamos dizer que voc&ecirc; queira. Nesse caso h&aacute; uma forma de garantir que o evento de auto-crescimento ocorra simultaneamente em todos os arquivos, o que, consequentemente, garantiria que voc&ecirc; continue a usar o Proportional Fill e, em um ambiente em que os arquivos possuam o mesmo percentual de espa&ccedil;o dispon&iacute;vel e configura&ccedil;&otilde;es de autogrowth id&ecirc;nticas, uma distribui&ccedil;&atilde;o de dados mais equitativa entre os arquivos deste Filegroup.</p>
<p>Aqui entra em cena a Trace Flag 1117. Eu costumo dizer que Trace Flags s&atilde;o como <em>Cheat Codes</em>. Se voc&ecirc; quer mudar algum comportamento padr&atilde;o do SQL, voc&ecirc; pode fazer uso delas, por&eacute;m fica aqui um ponto de aten&ccedil;&atilde;o: Todas elas devem ser cuidadosamente avaliadas antes de serem habilitadas. <br />Essa Trace Flag, ou TF, &eacute; bem interessante por sinal. Para o banco de dados Tempdb, ela &eacute; praticamente &ldquo;mandat&oacute;ria&rdquo;, afinal para eu garantir que n&atilde;o vou ter aqueles problemas de conten&ccedil;&atilde;o nos mapas de aloca&ccedil;&atilde;o eu preciso garantir que todos os arquivos de dados do tempdb estejam sendo usados, e isso s&oacute; &eacute; poss&iacute;vel se todos tiverem espa&ccedil;o dispon&iacute;vel. Esse &eacute; um dos motivos que levaram a Microsoft a transformar a TF1117 para o banco de dados tempdb em um comportamento padr&atilde;o, a partir da vers&atilde;o 2016, ou seja, voc&ecirc; n&atilde;o precisa habilitar essa TF por causa do tempdb, apenas se voc&ecirc; quiser ter o mesmo comportamente para bancos de usu&aacute;rio, que &eacute; exatamente o que estamos falando aqui.</p>
<p>Habilitando essa TF, toda vez que o evento de auto-crescimento ocorre ele expande todos os arquivos de um determinado filegroup, simultaneamente.<br />Como todo TF, ou a maioria, varia muito a aplicabilidade em bancos de usu&aacute;rio. O TF 1117 &eacute; um deles.</p>
<p>Ent&atilde;o resumindo essa parte: n&oacute;s temos este algoritmo, que falamos aqui, o Proportional Fill, que &eacute; utilizado para garantir que todos os arquivos de um determinado FG cheguem ao seu limite "aproximadamente" ao mesmo tempo (FULL). A quest&atilde;o &eacute;, chegamos no limite de TODOS os arquivos, a distribui&ccedil;&atilde;o dos dados deixa de ser proporcional e passa a utilizar apenas um dos arquivos, j&aacute; que o event auto-grow &eacute; RR (round-robin), como eu j&aacute; mencionei.</p>
<p>Mais uma vez, do ponto de vista de desempenho, distribuir os dados entre diversos arquivos que est&atilde;o no mesmo disco, n&atilde;o faria muita diferen&ccedil;a. A conten&ccedil;&atilde;o de mapas de aloca&ccedil;&atilde;o em banco de dados de usu&aacute;rio &eacute; rara, por isso, a quest&atilde;o aqui s&atilde;o os benef&iacute;cios de se compartilhar spindles, ou seja, a capacidade de IO dos discos, considerando que voc&ecirc; possa alocar cada um desses arquivos em um discos distinto.</p>
<p><strong>Habilitar essa TF e utilizar o Proportional Fill se aplica ao meu cen&aacute;rio?</strong> <br /><br />Talvez.</p>
<p>Lembre-se de que temos funcionalidades muito bacanas que podem te ajudar do ponto de vista de performance e tamb&eacute;m distribuir os dados entre diversos arquivos e discos, como as Tabelas Particionadas, que inclusive fazem uso dos Filegroups para fazer isso acontecer. Contudo, em cen&aacute;rios que voc&ecirc; simplesmente n&atilde;o pode utilizar determinadas solu&ccedil;&otilde;es como essa, abusar do Proportional FIll n&atilde;o seria nenhum pecado.</p>
<p>Apenas para citar um exemplo de aplicabilidade. Eu visitei um cliente aqui nos EUA onde um determinado ambiente &nbsp;tinha apenas um FG com diversos (muitos mesmo) arquivos de dados, distribu&iacute;dos entre v&aacute;rios discos, e o banco j&aacute; possuia aproximadamente 20TB de dados. Infelizmente neste cen&aacute;rio havia alguns problemas de design e acredito que 80% das minhas recomenda&ccedil;&otilde;es foram nesse sentido. Mas a d&uacute;vida do cliente era: Como eu posso distribuir melhor meus dados entre esses v&aacute;rios arquivos? Como garantir uma distribui&ccedil;&atilde;o mais equitativa entre eles?</p>
<p>Infelizmente n&atilde;o teria como eu simplesmente fazer um DROP e CREATE de todas as tabelas. A menos que voc&ecirc; opte por utilizar Tabelas Particionadas, o que n&atilde;o foi o caso desse cliente, seria imposs&iacute;vel redistribuir esses dados. Por&eacute;m os &iacute;ndices poderiam ser redistribu&iacute;dos, afinal o REBUILD iria movimentar minhas p&aacute;ginas de &iacute;ndices de qualquer jeito, e a&iacute; dependendo de quanto espa&ccedil;o eu tenho dispon&iacute;vel em cada arquivo, o SQL Server poderia redistribuir esses dados. E foi assim que fizemos a redistribui&ccedil;&atilde;o dos dados entre os arquivos, para que pudessemos garantir um % de espa&ccedil;o dispon&iacute;vel mais parecido entre os arquivos e utilizar uma distribui&ccedil;&atilde;o mais equitativa no caso de novas aloca&ccedil;&otilde;es.</p>
<p>N&atilde;o foi f&aacute;cil, mas a id&eacute;ia nesse caso foi brincar com o Proportional Fill. Aumentando o % de espa&ccedil;o dispon&iacute;vel nos arquivos (alterando o tamanho inicial deles) que ele queria que mais dados fossem alocados. Ap&oacute;s alguns Rebuilds nos &iacute;ndices isso ocorreu. Para as tabelas Heap, simplesmente criamos um &iacute;ndice clustered para fazer a m&aacute;gica. Se ele resolveu o problem de design dele? N&atilde;o. Mas o algoritmo Proportional Fill ajudou a resolver algo que para este cliente era um problema. Hoje ele tem um ambiente mais previs&iacute;vel e reportou um maior desempenho, inclusive, j&aacute; que ele tem uma distribui&ccedil;&atilde;o de dados equitativa entre v&aacute;rios arquivos que est&atilde;o em discos distintos.</p>
<p>Deixando um pouco de lado o Proportional Fill e falando novamente do TF 1117. A grande quest&atilde;o &eacute; realmente o que voc&ecirc; espera do seu ambiente.</p>
<p>N&atilde;o vou aqui advogar a favor ou contra utilizar essa TF.<br />A quest&atilde;o &nbsp;&eacute;: Voc&ecirc; quer manter as distribui&ccedil;&otilde;es entre mais de um arquivo de um determinado FG, habilite, simples assim. Ok, n&atilde;o &eacute; legal manter o auto-grow autom&aacute;tico. Concordo plenamente, apesar de eu ter mencionado uma forma mais "suave" de se fazer (Instant File Initialization + crescimento em MB). Mas garanto uma coisa, h&aacute; sim &iacute;ndicios claros de aumento de desempenho nas aloca&ccedil;&atilde;o dos dados em ambientes que possuem um cen&aacute;rio de distribui&ccedil;&atilde;o por igual entre diversos arquivos, desde que pertencentes a um mesmo FG e, mais uma vez, desde que os spindles, ou seja, a capacidade de leitura e escrita dos discos sejam distintas, j&aacute; que diferente do tempdb, n&atilde;o necessariamente temos um grande benef&iacute;cio em ter v&aacute;rios arquivos simplesmente focando na redu&ccedil;&atilde;o da conten&ccedil;&atilde;o de mapas de aloca&ccedil;&atilde;o/PFS em bancos de usu&aacute;rio.</p>
<p>Dica final e um <em>disclaimer</em> sobre meu post:</p>
<p><strong>Nunca mude configura&ccedil;&otilde;es como essa sem antes testar e garantir que isso &eacute; o melhor para seu ambiente produtivo.</strong></p>
<p>No final do post voc&ecirc; econtra um link para alguns scripts que voc&ecirc; pode utilizar para testar o Proportional FIll. O primeiro arquivo &eacute; uma demonstra&ccedil;&atilde;o de como seria a distribui&ccedil;&atilde;o proporcional, quando temos arquivos com % de espa&ccedil;o dispon&iacute;vel diferentes entre eles. O segundo mostra como, garantindo o mesmo espa&ccedil;o dispon&iacute;vel, faz com que o SQL Server mantenha uma distribui&ccedil;&atilde;o equitativa. Veja tamb&eacute;m como ocorre o evento de auto-crescimento, antes e ap&oacute;s habilitar o TF1117. Se preferir ver a DEMO, ao inv&eacute;s de voc&ecirc; mesmo testar, no webcast que citei no in&iacute;cio do artigo eu utilizo esses scripts para a minha demonstra&ccedil;&atilde;o.</p>
<p>Boa sorte na administra&ccedil;&atilde;o dos seus dados!</p>
<p>Thiago Caserta.<br />&nbsp;<br />&nbsp;</p>
<p><strong>LINK PARA DOWNLOAD DOS SCRIPTS:&nbsp;<a href="http://1drv.ms/1LzoOUR">http://1drv.ms/1LzoOUR</a></strong></p>]]></content:encoded>
    </item>
    <item>
      <title>O "problema" de queries Ad Hoc e um pouco sobre Forced Parameterization</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/o-problema-de-queries-ad-hoc-e-um-pouco-sobre-forced-parameterization</link>
      <pubDate>Mon, 21 Sep 2015 08:26:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/09/21/o-problema-de-queries-ad-hoc-e-um-pouco-sobre-forced-parameterization/</guid>
      <description><![CDATA[Hoje na lista de email dos PFEs de SQL Server do Brasil, meu amigo Diego Miranda encaminhou um post...]]></description>
      <content:encoded><![CDATA[<p>Hoje na lista de email dos PFEs de SQL Server do Brasil, meu amigo Diego Miranda encaminhou um post bacana do Jack Li (Escalation Engineer) falando sobre a op&ccedil;&atilde;o Forced Parameterization (<a href="http://blogs.msdn.com/b/psssql/archive/2015/04/22/forced-parameterization-to-the-rescue.aspx">http://blogs.msdn.com/b/psssql/archive/2015/04/22/forced-parameterization-to-the-rescue.aspx</a>).<br /> <br /> Resolvi escrever um post r&aacute;pido sobre isso.<br /> <br /> &Eacute; interessante notar que em ambientes onde queries Ad Hoc representam um percentual consider&aacute;vel do workload total, a quantidade de complia&ccedil;&otilde;es pode se tornar um problema, independente do tamanho do servidor. O motivo &eacute; simples, o SQL Server, por padr&atilde;o, produz diferentes planos de execu&ccedil;&atilde;o para cada query Ad Hoc que n&atilde;o possui a mesma defini&ccedil;&atilde;o (incluindo valores).<br /> <br /> Por exemplo:<br /> <br /> <strong>Query 1</strong></p>
<pre class="scroll"><code class="mysql">SELECT Coluna1, Coluna2, Coluna3 FROM Tabela WHERE Coluna1 = 'A'</code></pre>
<p>Aqui o SQL compilaria e guardaria no cache o plano de execu&ccedil;&atilde;o utilizado para encontrar registros onde o valor = A.<br /> <br /> <strong>Query 2</strong></p>
<pre class="scroll"><code class="mysql">SELECT Coluna1, Coluna1, Coluna1 FROM Tabela WHERE Coluna1 = 'B'</code></pre>
<p><br /> Bem, numa execu&ccedil;&atilde;o parametrizada (Uma stored procedure, por exemplo), o SQL Server simplesmente poderia reutilizar o plano da primeira query j&aacute; que a mudan&ccedil;a foi m&iacute;nima (apenas o valor utilizado no filtro), por&eacute;m a engine relacional entende como uma nova query, ou seja, durante o processo de otimiza&ccedil;&atilde;o da query o Query Optmizer recebe um cache miss, que basicamente indica que n&atilde;o h&aacute; um plano de execu&ccedil;&atilde;o existente para esta query e ele ent&atilde;o &eacute; respons&aacute;vel por gerar e armazenar esse novo plano no cache, mesmo sendo praticamente igual ao plano anterior. &Eacute; claro que se voc&ecirc; executar a Query 1 novamente, como j&aacute; existe um plano que satisfa&ccedil;a essa consulta em cache o SQL Server o reutilizaria.<br /> <br /> A quest&atilde;o &eacute;, par&acirc;metros podem afetar a efetividade da minha Query? A resposta: Sim, podem! <br />Imagine que para a a Query 1 existam 10 registros que correspondem ao filtro utilizado (A). Para a Query 2 h&aacute; 10.000 registros. Nesse caso o plano de execu&ccedil;&atilde;o utilizado para a Query 1 pode ser ineficiente para a Query 2, o que poderia impactar a execu&ccedil;&atilde;o da Query 2 e consequemente degradar a performance da sua aplica&ccedil;&atilde;o.<br /> <br /> Isso &eacute; o que chamamos de Parameter Sniffing, muito comum em Stored Procedures. Por que em Stored Procedures? Simplesmente porque a grande diferen&ccedil;a (ok! H&aacute; outras diferen&ccedil;as, claro) entre executar uma query Ad Hoc ou uma Stored Procedure &eacute; que o SQL Server otmiza a execu&ccedil;&atilde;o de Procedures por parametriz&aacute;-las, ou seja, reutilizar os planos de execu&ccedil;&atilde;o gerados na primeira execu&ccedil;&atilde;o da Procedure. N&atilde;o vou falar muito sobre o Parameter Sniffing neste momento, pois o meu foco era pontuar a op&ccedil;&atilde;o mencionada pelo Jack Li.<br /> <br /> Quais op&ccedil;&otilde;es eu tenho para diminuir o n&uacute;mero de compila&ccedil;&otilde;es? Bem, se voc&ecirc; acredita que a grande maioria das suas queries utilizam planos similares para serem executadas, voc&ecirc; poderia utilizar a op&ccedil;&atilde;o que o Jack menciona no seu post, aqui tamb&eacute;m pode ser uma op&ccedil;&atilde;o em ambientes os quais voc&ecirc; n&atilde;o pode fazer mudan&ccedil;as nas queries em si. <br />Uma outra op&ccedil;&atilde;o, que envolve mudan&ccedil;a nas queries, seria a de executar suas queries utilizando a system stored procedure sp_executesql. Quando utilizada, voc&ecirc; est&aacute; basicamente for&ccedil;ando a parametriza&ccedil;&atilde;o da query. Por exemplo:</p>
<pre class="scroll"><code class="cplusplus">EXECUTE sp_executesql <br /> N'SELECT Coluna1, Coluna2, Coluna3 FROM Tabela WHERE Coluna1 = @valor',<br /> N'@valor varchar(1)',<br /> @valor = 'A'; </code></pre>
<p><br />Nesta execu&ccedil;&atilde;o, se observarmos o plano armazenado em cache seria algo mais ou menos assim: SELECT Coluna1, Coluna2, Coluna3 FROM Tabela WHERE Coluna1 = @valor.&nbsp;Ou seja, n&atilde;o h&aacute; um valor espec&iacute;fico armazenado junto ao plano, o que faz com que a pr&oacute;xima execu&ccedil;&atilde;o, independente do par&acirc;metro utilizado, encontre um plano satisfat&oacute;rio j&aacute; armazenado em cache.</p>
<p>&Eacute; claro que h&aacute; muitos outros detalhes importantes a se avaliar.<br /><br /> Como eu mencionei na nossa discuss&atilde;o interna, h&aacute; uma pequena linha entre essa op&ccedil;&atilde;o ser boa ou n&atilde;o para um determinado ambiente, j&aacute; que um plano pode ser realmente bom para v&aacute;rias queries e a&iacute; reduzir o n&uacute;mero de compila&ccedil;&otilde;es e consequentemente o tempo de CPU (e mem&oacute;ria consumida) ou impactar v&aacute;rias das queries porque cada uma gosta de um plano espec&iacute;fico. <br /> &nbsp;<br /> O que eu realmente gostei do post do Jack Li foi o que ele mencionou no final: If things don&rsquo;t work out, it&rsquo;s easy to back it out. Over the course of troubleshooting performance issues, I have used this trick many times. <br /><br /> Muitas vezes a gente fica pensando, ser&aacute; que eu altero ou n&atilde;o? <br />H&aacute; coisas que s&oacute; "testando" pra saber. A dica que eu dou &eacute;, investigue se a quantidade de queries Ad Hoc sendo executadas no seu ambiente est&aacute; impactando o seu ambiente (alto consumo de CPU e/ou mem&oacute;ria por elas &eacute; uma boa indica&ccedil;&atilde;o + Avalie a quantidade de compila&ccedil;&otilde;es por segundo). <br />Esses dois inputs geralmente v&atilde;o determinar se mudan&ccedil;as como essas devem ser feitas ou n&atilde;o, Tenha sempre em mente que Procedures s&atilde;o prefer&iacute;evis do que Ad Hoc - Best Practice.</p>
<p>H&aacute; outros aspectos que quero ir considerando nos meus posts futuros relacionados a performance, mas como eu disse, esse era pra ser um post r&aacute;pido. &nbsp; :)<br /><br />Lembre-se performance &eacute; uma ci&ecirc;ncia "relativamente" exata, por&eacute;m pode ser bem tricky, e varia consideravelmente dependendo do comportamente das suas aplica&ccedil;&otilde;es.<br /> &nbsp;<br /> At&eacute; o pr&oacute;ximo post.<br /><br /> Um abra&ccedil;o,<br /> Thiago Caserta,</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Webcast: SQL Server - Distribuição de dados e o algoritmo Proportional Fill</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/webcast-sql-server-distribuio-de-dados-e-o-algoritmo-proportional-fill</link>
      <pubDate>Tue, 15 Sep 2015 08:06:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/09/15/webcast-sql-server-distribuio-de-dados-e-o-algoritmo-proportional-fill/</guid>
      <description><![CDATA[No dia 22 de Setembro, irei participar como palestrante na s&eacute;rie de webcasts do...]]></description>
      <content:encoded><![CDATA[<p>No dia 22 de Setembro, irei participar como palestrante na s&eacute;rie de webcasts do grupo&nbsp;<a href="https://plus.google.com/u/0/107133671617566409544/posts">SQL Maniacs</a> do meu amigo <a href="https://vfava.wordpress.com/">Vitor Fava</a>.<br />O tema escolhido foi: Distribui&ccedil;&atilde;o de dados e o algoritmo Proportional Fill. Acho esse um tema pouco abordado no geral e resolvi criar uma apresenta&ccedil;&atilde;o com uma vis&atilde;o geral sobre como funciona a aloca&ccedil;&atilde;o de dados no SQL Server do ponto de vista da distribui&ccedil;&atilde;o entre diversos arquivos de dados.</p>
<p>Pra participar n&atilde;o precisa de inscri&ccedil;&atilde;o, basta acessar o link do hangout no Youtube no dia e hor&aacute;rio do evento:&nbsp;<a href="https://www.youtube.com/watch?v=XXbVLzfKwsQ">https://www.youtube.com/watch?v=XXbVLzfKwsQ</a></p>
<p><strong>Descri&ccedil;&atilde;o:</strong> <br />O SQL Server &eacute; um produto fascinante e relativamente complexo, principalmente quando avaliamos aspectos internos da plataforma de dados da Microsoft. Voc&ecirc; j&aacute; se perguntou como funciona a distribui&ccedil;&atilde;o de dados no SQL Server quando voc&ecirc; possui mais de um arquivo de dados (.mdf, .ndf) para o mesmo banco de dados? Talvez voc&ecirc; tenha bem claro o conceito de arquivos, p&aacute;ginas e objetos, mas o que dizer sobre a distribui&ccedil;&atilde;o de dados? Infelizmente n&atilde;o seria poss&iacute;vel cobrir aspectos t&atilde;o profundos como a aloca&ccedil;&atilde;o de registros em si (GAMs, SGAMs, IAM, PFS) mas espero falar disso numa pr&oacute;xima sess&atilde;o. O que esperar desse webcast ent&atilde;o? Uma vis&atilde;o geral sobre arquivos e p&aacute;ginas e como voc&ecirc; pode otimizar as aloca&ccedil;&otilde;es de dados utilizando v&aacute;rios arquivos. Tamb&eacute;m vamos cobrir o papel do File Group em um banco de dados SQL Server. Vamos mostrar como funciona a distribui&ccedil;&atilde;o de dados em v&aacute;rios arquivos e como um algor&iacute;timo chamado Proportional Fill pode ajudar, ou n&atilde;o, a aumentar a performance das suas aloca&ccedil;&otilde;es de dados e, consequentemente, suas aplica&ccedil;&otilde;es.</p>
<p><strong>Data:</strong> Dia 22 de Setembro de 2015 21:00 - Hor&aacute;rio de Bras&iacute;lia</p>
<p><strong>Local:</strong> Google Hangout -&nbsp;<a href="https://www.youtube.com/watch?v=XXbVLzfKwsQ">https://www.youtube.com/watch?v=XXbVLzfKwsQ</a></p>
<p><strong>Palestrante:</strong> Thiago Caserta</p>
<p><span>Vejo voc&ecirc; l&aacute;!</span></p>
<p>Thiago Caserta.</p>]]></content:encoded>
    </item>
    <item>
      <title>AlwaysOn Availability Group em Cluster MultiSubnet - Erros de conexão e Paramêtros importantes relacionados ao Listener</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/alwayson-availability-group-em-cluster-multisubnet-erros-de-conexo-e-paramtros-importantes-relacionados-ao-listener</link>
      <pubDate>Wed, 02 Sep 2015 09:07:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/09/02/alwayson-availability-group-em-cluster-multisubnet-erros-de-conexo-e-paramtros-importantes-relacionados-ao-listener/</guid>
      <description><![CDATA[Trabalhando com diversos clientes, percebo que muitos desenvolvedores tem d&uacute;vidas de como...]]></description>
      <content:encoded><![CDATA[<p>Trabalhando com diversos clientes, percebo que muitos desenvolvedores tem d&uacute;vidas de como configurar uma string de conex&atilde;o usando o SQL Server AlwaysOn Availability Group Listener em um cluster Multi Subnet. &Eacute; interessante que essa &eacute; uma d&uacute;vida bem comum e, em diversos clientes percebi a necessidade de direcionar para a solu&ccedil;&atilde;o. Resolvi escrever este artigo j&aacute; que percebo que n&atilde;o h&aacute; muita informa&ccedil;&atilde;o sobre isso em portugu&ecirc;s.<br /><br /> Num cluster local, o qual involve, geralmente, apenas um &uacute;nico endere&ccedil;o TCP IP para o Availability Group Listener, n&atilde;o h&aacute; a necessidade de nenhuma mudan&ccedil;a. O cliente ir&aacute; apontar para o endere&ccedil;o IP do Listener ou o nome deste Listener (DNS Name) e a conex&atilde;o ocorrer&aacute; com sucesso. Por&eacute;m quando o Availbility Group involve mais de uma Subnet, onde h&aacute; geralmente dois IPs associados, um para cada Subnet, o cliente ent&atilde;o precisar&aacute; utilizar o nome do Listener para garantir a transpar&ecirc;ncia para a aplica&ccedil;&atilde;o em caso de Failover.&nbsp;Se o desenvolvedor utilizar uma string de conex&atilde;o sem os par&acirc;metros corretos, suas conex&otilde;es recebem erros de timeout e voc&ecirc; provavelmente percebe que &eacute; um problema intermitente e n&atilde;o necessariamente para todas as conex&otilde;es.</p>
<p><br /> Bem, vamos tentar explicar o porque isso acontece. <br /> Por padr&atilde;o, quando um Availability Group Listener &eacute; criado, h&aacute; uma op&ccedil;&atilde;o chamada RegisterAllProvidersIP que &eacute; configurada com o valor 1 (True). Esta configura&ccedil;&atilde;o &eacute; associada ao recurso Network Name (vinculado ao Listener) no Failover Cluster Manager. Isso significa que os endere&ccedil;os IP de ambas as localidades (Subnet 1 e 2) ir&atilde;o ser adicionados ao registro DNS do cliente (DNS A-record). Quando o cliente tenta acessar o Availability Group atrav&eacute;s do Listener ele, arbitrariamente ou ramdomicamente (se existisse essa palavra, hehe), tenta conectar a um dos dois endere&ccedil;os IP associados. Numa l&oacute;gica r&aacute;pida ent&atilde;o, poder&iacute;amos dizer que aproximadamente 50% de todas os acessos ir&atilde;o receber erros de timeout e, por isso que voc&ecirc; percebe que algumas conex&otilde;es ocorrem com sucesso. A solu&ccedil;&atilde;o mais elegante e a que eu recomendo &eacute; a de utilizar um param&ecirc;tro adicional na string de conex&atilde;o das suas aplica&ccedil;&otilde;es. Este par&acirc;metro se chama MultiSubnetFailover.<br /> Explicando de forma simples, quando o cliente tenta acessar o AG atrav&eacute;s do Listener, com a op&ccedil;&atilde;o MultiSubnetFailover ao inv&eacute;s de acessar um IP de forma arbitr&aacute;rio, o cliente realiza acesso simultaneo aos IP associados ao AG Listener (dependendo da forma que a conex&atilde;o &eacute; feita ele pode simplesmente for&ccedil;ar o retry da conex&atilde;o a ocorrer de forma mais r&aacute;pida). O IP que responder &eacute; o que o cliente/aplica&ccedil;&atilde;o ir&aacute; utilizar. Esta &eacute; uma forma de acesso mais precisa e na minha conclus&atilde;o irei dar mais alguns detalhes do porque esta op&ccedil;&atilde;o &eacute; prefer&iacute;vel comparada a uma outra op&ccedil;&atilde;o dispon&iacute;vel que irei comentar a seguir.<br /> Ah! Mais um detalhe, para aplica&ccedil;&otilde;es que fazem usam de drivers ao inv&eacute;s de conex&otilde;es diretas atrav&eacute;s de string de conex&atilde;o, o driver SQL Native Client, a partir da vers&atilde;o 11, suporta esta op&ccedil;&atilde;o (MultiSubnetCluster)<br /> <br /> <strong>RegisterAllProvidersIP + HostRecordTTL</strong><br /> <br /> Infelizmente, H&aacute; aplica&ccedil;&otilde;es que n&atilde;o suportam a op&ccedil;&atilde;o MultiSubnetFailover, por diversos motivos (uma aplica&ccedil;&atilde;o legacy ou &eacute; aquela famosa caixinha fechada a qual a empresa que desenvolveu n&atilde;o existe mais ou n&atilde;o &eacute; favor&aacute;vel a fazer mudan&ccedil;as). Nesse caso voc&ecirc; pode recorrer a mudan&ccedil;as nos par&acirc;metros <em>RegisterAllProvidersIP</em> e <em>HostRecordTTL</em>. <br /> <br /> Mudando a configura&ccedil;&atilde;o RegisterAllProvidersIP para 0, o &uacute;nico IP que estiver Online ser&aacute; o IP registrado junto ao DNS do cliente. H&aacute; apenas uma considera&ccedil;&atilde;o aqui que nos leva a falar do pr&oacute;ximo par&acirc;metro a ser alterado, o HostRecordTTL. Quando um failover ocorre entre inst&acirc;ncias de diferentes Subnets, as configura&ccedil;&otilde;es de DNS podem impactar diretamente a conectividade das aplica&ccedil;&otilde;es. H&aacute; uma propriedade relacionada ao DNS conhecida como TTL ou Time to Live, de forma simples podemos dizer que ela &eacute; respons&aacute;vel por dizer de quanto em quanto tempo o registro DNS de cada cliente ser&aacute; atualizado. Se o Listener mudar o endere&ccedil;o IP em que ele est&aacute; respondendo (no caso de um Failover do AG entre Subnets distintas) isso n&atilde;o afeta diretamente na atualiza&ccedil;&atilde;o do registro DNS do cliente, o que pode fazer com que ele ainda tente acessar o Availability Group utilizando o endere&ccedil;o TCP IP anterior (o IP utilizado na Subnet 1, por exemplo). Quando a replica&ccedil;&atilde;o dos registros DNS ocorre para a m&aacute;quina do cliente ent&atilde;o, todos os registros s&atilde;o atualizados e seus clientes poder&atilde;o utilizar o endere&ccedil;o IP correto (utilizado na Subnet 2). <br /> Por padr&atilde;o, essa atualiza&ccedil;&atilde;o/replica&ccedil;&atilde;o ocorre a cada 20 minutos, o que significa que voc&ecirc; poderia ficar aguardando at&eacute; 20 minutos para ser poss&iacute;vel conectar com sucesso ao AG utilizando o Listener's Name. Para que essa replica&ccedil;&atilde;o ocorra num tempo menor, &eacute; poss&iacute;vel reduzir o par&acirc;metro TTL, for&ccedil;ando essa atualiza&ccedil;&atilde;o a ocorrer de forma mais frequente. Se voc&ecirc; pesquisar em algumas documenta&ccedil;&otilde;es da Microsoft &eacute; recomend&aacute;vel diminuir esse par&acirc;metro para, no m&iacute;nimo, 5 minutos (ou 300 segundos - a configura&ccedil;&atilde;o &eacute; em segundos), mas segundo a minha experi&ecirc;ncia e de acordo com a sua necessidade de neg&oacute;cios da sua empresa, voc&ecirc; pode alterar at&eacute; para um valor menor, talvez algo entre 2 e 3 minutos (120-180 segundos). Claro que quanto menor o valor para a configura&ccedil;&atilde;o HostRecordTTL existe um leve aumento no tr&aacute;fego da sua rede, devido a requisi&ccedil;&atilde;o constante de registros DNS.<br /> <br /> Lembrando que essas configura&ccedil;&otilde;es de HostRecordTTL e RegisterAllProvidersIP s&atilde;o feitas diretamente no recurso do Listener no Failover Cluster Manager, n&atilde;o no Active Directory ou no DNS, apesar de estarem relacionados. O time de AlwaysOn da Microsoft tem um artigo bem bacana sobre essas op&ccedil;&otilde;es, incluindo um script Powershell que pode te ajudar a mudar essas configura&ccedil;&otilde;es de forma mais simples e r&aacute;pida.<br /> <br /> http://blogs.msdn.com/b/alwaysonpro/archive/2014/06/03/connection-timeouts-in-multi-subnet-availability-group.aspx<br /> <br /> <strong>Conclus&atilde;o</strong><br /> <br /> Apesar de a op&ccedil;&atilde;o de mudar os par&acirc;metros <em>RegisterAllProvidersIP</em> e <em>HostRecordTTL</em> ser uma solu&ccedil;&atilde;o interessante para clientes que n&atilde;o possuem suporte a op&ccedil;&atilde;o MultiSubnetFailover, o par&acirc;metro MultiSubnetFailover &eacute;, sem d&uacute;vida, a melhor forma de acessar seu AG em um cluster Multi-Subnet atrav&eacute;s do Listener. Al&eacute;m de ser mais preciso, pois quando o cliente tenta acessar o AG atrav&eacute;s do Listener n&atilde;o ir&aacute; acessar obrigat&oacute;riamente um IP aleat&oacute;rio, podemos evitar erros de timeout causados pela lat&ecirc;ncia na replica&ccedil;&atilde;o dos registros DNS devido as propriedades de TTL. <br /><br />Espero poder trazer mais dicas e explica&ccedil;&otilde;es focadas em Alta Disponibilidade em breve.</p>
<p>&nbsp;</p>
<p>At&eacute; l&aacute;!<br /> <br /> Um abra&ccedil;o,<br /> Thiago Caserta.</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>[Troubleshooting] Diferenças de comportamento da opção 'QUOTE_IDENTIFIER'</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/troubleshooting-diferenas-de-comportamento-da-opo-quote_identifier</link>
      <pubDate>Sat, 27 Jun 2015 17:27:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/06/27/troubleshooting-diferenas-de-comportamento-da-opo-quote_identifier/</guid>
      <description><![CDATA[Este problema ocorreu na verdade h&aacute; alguns anos, logo que comecei a trabalhar como PFE, acho...]]></description>
      <content:encoded><![CDATA[<div><br />Este problema ocorreu na verdade h&aacute; alguns anos, logo que comecei a trabalhar como PFE, acho que por isso mesmo lembro detalhadamente dessas informa&ccedil;&otilde;es.&nbsp;Com novas vers&otilde;es sendo lan&ccedil;adas no m&iacute;nimo a cada dois anos, quero procurar&nbsp;manter os posts focados em novas vers&otilde;es e funcionalidades, mas como se trata de um post sobre troubleshooting, n&atilde;o acho errado falar um pouquinho sobre uma vers&atilde;o ainda muito comum na maioria dos clientes que atuo (SQL Server 2008 R2). <br />Quero deixar este post como refer&ecirc;ncia caso algu&eacute;m passe pela mesma situa&ccedil;&atilde;o algum dia. Se voc&ecirc; encontrou este post porque est&aacute; passando por este problema: Lucky you, enjoy! <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;"><span style="font-size: small;">J</span></span></span></div>
<div>
<p style="margin: 0in 0in 0pt;"><br /><strong>Cen&aacute;rio:</strong></p>
</div>
<div>Cliente X&nbsp;desejava executar uma procedure que manipulava informa&ccedil;&otilde;es em formato XML. A inst&acirc;ncia SQL Server havia sido migrada para SQL Server 2008 R2 h&aacute; pouco menos de uma semana.</div>
<div><strong><br />Problema:</strong></div>
<div>Foi reportado o seguinte erro, ao tentar executar uma procedure com processamento de informa&ccedil;&otilde;es XML:<br /><br /></div>
<div style="padding-left: 30px;"><em>SELECT failed because the following SET options have incorrect settings:</em><br /><em>'QUOTE_IDENTIFIER'. Verify set options are correct for use indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data types methods and/or spatial index operations.</em></div>
<div><strong><br />Informa&ccedil;&otilde;es adicionais:</strong></div>
<ul>
<li>Tal erro persistia mesmo com a op&ccedil;&atilde;o SET QUOTED_IDENTIFIER&nbsp;ON sendo definida no n&iacute;vel da&nbsp;sess&atilde;o;</li>
<li>A mensagem ocorre apenas quando o banco de dados est&aacute; em Compatibility Level 100. Quando o banco de dados &eacute; reconfigurado para Compatibility Level 90 (SQL 2005)&nbsp;a procedure era executada com sucesso.</li>
</ul>
<div><strong>Explica&ccedil;&atilde;o:</strong></div>
<div>Ap&oacute;s alguns testes conclu&iacute;mos que a procedure havia sido criada com a op&ccedil;&atilde;o SET QUOTED_IDENTIFIER OFF. Tal conclus&atilde;o se d&aacute; pelo fato de que o SQL Server 2008 utiliza a op&ccedil;&atilde;o QUOTED_IDENTIFIER utilizada no momento da cria&ccedil;&atilde;o da stored procedure, ou seja, mesmo for&ccedil;ando o SET QUOTED_IDENTIFIER ON na sess&atilde;o que est&aacute; executando a procedure, o SQL Server ignora a op&ccedil;&atilde;o da sess&atilde;o e passa a utilizar apenas o que foi definido no momento da cria&ccedil;&atilde;o.<br />J&aacute; o SQL Server 2005, utiliza a op&ccedil;&atilde;o da sess&atilde;o que est&aacute; executando a procedure, independente do que foi definido na cria&ccedil;&atilde;o do objeto. Como todas as sess&otilde;es abertas contra o banco de dados, por padr&atilde;o, s&atilde;o QUOTED_IDENTIFIER ON, for&ccedil;ando ou n&atilde;o a utiliza&ccedil;&atilde;o desta op&ccedil;&atilde;o, a procedure &eacute; executada com sucesso em bancos de dados com o Compatibility Level 90.<br />&nbsp;</div>
<div><strong>Recomenda&ccedil;&atilde;o:</strong></div>
<div>Para resolu&ccedil;&atilde;o deste problema recomendamos o cliente a manter o banco de dados em Compatibility Level 100 e alterar a procedure incluindo a op&ccedil;&atilde;o SET QUOTED_IDENTIFIER ON.<br />Dessa forma, o c&oacute;digo de altera&ccedil;&atilde;o da procedure ficaria da seguinte forma:</div>
<div style="padding-left: 30px;"><br />SET QUOTED_IDENTIFIER ON;</div>
<div style="padding-left: 30px;">GO</div>
<div style="padding-left: 30px;">ALTER PROCEDURE &hellip;</div>
<div><strong><br />Refer&ecirc;ncias:<br /></strong></div>
<div><br /><strong>SET QUOTED_IDENTIFIER (Transact-SQL)</strong><br /><a href="http://msdn.microsoft.com/pt-br/library/ms174393.aspx">http://msdn.microsoft.com/pt-br/library/ms174393.aspx</a></div>
<div><br /><strong>Differences Between Lower Compatibility Levels and Level 100</strong><br /><a href="http://msdn.microsoft.com/en-us/library/bb510680.aspx">http://msdn.microsoft.com/en-us/library/bb510680.aspx</a></div>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server 2014 In-Memory OLTP - IO e Filestream - Perguntas Respondidas</title>
      <link>https://docs.microsoft.com/archive/blogs/tcaserta/sql-server-2014-in-memory-oltp-io-e-filestream-perguntas-respondidas</link>
      <pubDate>Fri, 26 Jun 2015 17:47:00 GMT</pubDate>
      <dc:creator><![CDATA[Thiago Caserta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/tcaserta/2015/06/26/sql-server-2014-in-memory-oltp-io-e-filestream-perguntas-respondidas/</guid>
      <description><![CDATA[Essa semana resolvi postar algumas perguntas respondidas sobre detalhes do SQL Server Hekaton, ou...]]></description>
      <content:encoded><![CDATA[<p>Essa semana resolvi postar algumas perguntas respondidas sobre detalhes do SQL Server Hekaton, ou In-Memory OLTP, que est&aacute; dispon&iacute;vel na vers&atilde;o 2014 do SQL Server e obviamente estar&aacute; tamb&eacute;m presente na vers&atilde;o 2016. Apenas lembrando que esta &eacute; uma feature da edi&ccedil;&atilde;o Enterprise.<br /><br />Espero que gostem e continuem a fomentar as dicuss&otilde;es sobre In-Memory OLTP com perguntas interessantes como as que postei aqui. Posteriormente vou criar outros posts com as respostas.<br /><br /></p>
<p><strong>A feature filestream &eacute; requerida para utiliza&ccedil;&atilde;o de&nbsp;tabelas persistentes com o In-Memory OLTP (durable tables)?</strong><br />O Hekaton - n&atilde;o sei porque, mas ainda&nbsp;gosto de usar o code-name da feature :) -&nbsp;usa a tecnologia Filestream apenas por tr&aacute;s dos bastidores, n&atilde;o estamos aqui falando de um FILESTREAM filegroup, pois a feature utiliza o &ldquo;Memory Optimized Data&rdquo; (MOD) filegroup.&nbsp; Voc&ecirc; n&atilde;o precisa habilitar a feature FILESTREAM, e sim apenas adicionar um Memory-Optimized Data filegroup.<br /><br /><strong>Falando sobre InMemory Databases, seria uma boa pr&aacute;tica dedicar um disco espec&iacute;fico para Filestream?</strong><br />O armazenamento dos MOD filegroup &eacute; apenas cr&iacute;tico durante a inicializa&ccedil;&atilde;o do SQL Server (quando o banco de dados est&aacute; sendo levado para o estado online). Neste momento, precisamos ler todas as informa&ccedil;&otilde;es daquele filegroup, com o objetivo de carregar todos os dados para mem&oacute;ria.&nbsp; Logo, dependendo de qu&atilde;o r&aacute;pido voc&ecirc; precisa que seja esta inicializa&ccedil;&atilde;o, voc&ecirc; pode colocar num disco compartilhado, num disco dedicado, ou at&eacute; mesmo em diversos discos (adicionando m&uacute;ltiplos containers) com o objetivo de paralelizar a leitura das informa&ccedil;&otilde;es dos containers. Discos SSD com toda certeza tamb&eacute;m seria de grande vantagem para que este processo ocorra de forma mais r&aacute;pida.<br /><br /><strong>A escrita nos containers (Schema_And_Data) &eacute; feita de forma r&acirc;mdomica ou sequencial?</strong> <br />A escrita nos arquivos de checkpoint dos MOD filegroups devem ser estritamente sequencial. Desta maneira &eacute; poss&iacute;vel fazer um melhor uso de IO de discos. Contudo, em algumas opera&ccedil;&otilde;es, veremos um pequeno percentual de escrita ramdomica causadas por escritas nos Delta files, mas podemos considerar esse percentual m&iacute;nimo.<br /><br /><strong>Em um cen&aacute;rio de Disaster Recovery com replicacao de storage, devo replicar meus discos Filestream?</strong><br />J&aacute; que os Memory Optimized Data filegroups cont&eacute;m os dados "persistentes" de qualquer durable table, caso voc&ecirc; n&atilde;o replique estes discos, os dados n&atilde;o estar&atilde;o dispon&iacute;veis no site remoto, e seus bancos de dados possivelmente n&atilde;o ficar&atilde;o online. At&eacute; a vers&atilde;o CTP1 (Community Technical Preview)&nbsp;do SQL 2014&nbsp;o AlwaysOn Availability Group n&atilde;o estava homologado para trabalhar com objetos In-Memory, por&eacute;m a partir da&nbsp;vers&atilde;o RTM, com o AlwaysOn AG seria poss&iacute;vel fazer a replica&ccedil;&atilde;o destes dados utilizando uma tecnologia nativa do pr&oacute;prio SQL Server.</p>
<p>Um abra&ccedil;o,</p>]]></content:encoded>
    </item>
  </channel>
</rss>