A memória é um dos recursos que formam o triângulo de desempenho – CPU e armazenamento são os outros dois. Se um for atingido, os outros dois assumem a carga para tentar trazer o desempenho para níveis aceitáveis, mas sempre há a desvantagem. Quaisquer transações que não possam ser confirmadas na memória, elas serão encaminhadas ao subsistema de disco pelo SQL Server. Isso causa um gargalo de desempenho. Portanto, as estatísticas de espera podem ajudar a identificar problemas de desempenho em um SQL Server.
Neste artigo, são abordados os seguintes tópicos:
- Noções internas da configuração e configuração de memória do SQL Server
- A memória do SQL Server e seu impacto no banco de dados e no desempenho do aplicativo
- Discutir vários componentes do SQL Server que contribuem para o uso de memória
- Práticas recomendadas e recomendações para dimensionamento de memória
- Relatório de memória de vários servidores
- E mais…
Gerenciamento de memória interno
O SQL Server possui uma Unidade de Gerenciamento de Memória que realiza o gerenciamento dinâmico automatizado de memória com base na carga de trabalho do sistema. Essa memória é o espaço volátil que é fundamental para as necessidades atuais de negócios – tecnologia, cujo dimensionamento correto é vital para o desempenho ideal dos aplicativos.
No entanto, todos sabemos que ao configurar o servidor, o dimensionamento contém alguns valores padrão. em alguns casos, logo descobrimos que o SQL Server usa quase toda a memória do servidor, mesmo que não haja atividade visível nos bancos de dados, trazendo as perguntas:Os valores padrão estão incorretos? Se sim, qual deve ser o tamanho certo?
O Gerenciamento de Memória no SQL Server funciona no algoritmo Fill-and-Flush. Os valores padrão não restringem o crescimento do consumo de memória, a menos que haja uma solicitação do sistema operacional.
O dimensionamento depende de vários componentes do sistema - em muitos casos, defini-lo entre 70% e 80% é um bom ponto de partida. Em seguida, você também deve monitorá-lo para ver o que mais pode estar faltando e se deve ajustar a configuração. Se você tiver outros serviços no SQL Server (você realmente não deveria), talvez seja necessário deixar mais para trás, especialmente se esses serviços consumirem muita memória. Considere revisitar a configuração de memória da instância SQL em qualquer um dos seguintes cenários:
- Falta de resposta do sistema operacional
- Esgotamento do aplicativo
- Operações de backup que exigem grandes buffers de memória
- Objetos otimizados na memória
- Índices de armazenamento de colunas, pois exigem grandes volumes de memória para realizar manutenções de índice.
A configuração de memória no SQL Server é bastante direta. Você pode alterar o valor usando sp_configure ou GUI do SSMS. Esta é uma opção online, mas lembre-se de que definir ou redefinir esses valores pode fazer com que alguns dos objetos de cache internos sejam reorganizados, o que deixará o sistema funcionando um pouco mais lento.
sp_configure ‘max server memory (MB)’,
Nesse caso, o número “2147483647” significa que o SQL Server não tem limite superior e usará toda a memória do servidor.
Min server memory:min server memory como valor mínimo; O SQL Server confirmará a memória para uso próprio até atingir a configuração de memória mínima do servidor. Depois disso, ele manterá pelo menos essa quantidade de memória utilizável.
Memória máxima do servidor:Da mesma forma que a memória mínima do servidor fornece um piso, a memória máxima do servidor fornece um teto.
Os níveis de memória mínimo e máximo são o limite inferior e superior da quantidade de memória permitida para uso pelo conjunto de buffers. O pool de buffers é a maior parte da memória consumida pelo SQL Server. A seguir estão os componentes do SQL Server na instância do SQL que usam memória do pool de buffers
- Cache de página de banco de dados
- Caches de log internos
- Cache de procedimento ou cache de plano de consulta
- Espaço de carga de trabalho de consulta
- Bloqueios (concessão de memória)
- Contexto de conexão
- Otimização de consultas
- Estruturas de dados no nível do sistema
Os valores das métricas importantes, como Mbytes Disponíveis, Páginas/Sec, Taxa de Acertos do Cache de Buffer, PLE, etc. determinam o desempenho do SQL Server.
Buffer Cache Hit Ratio é específico para cada aplicativo. 90% é geralmente considerado desejável. Isso significa que mais de 90% das solicitações foram atendidas pelo cache, o que é bom. Se o valor for menor, adicione mais memória até que seja consistentemente superior a 90%.
Os Bytes Disponíveis nada mais são do que uma indicação de quanta memória está disponível para uso. O contador Páginas/s mostra quantas páginas foram recuperadas do disco ou gravadas no disco, ambas devido a falhas de página de hardware.
PLE significa expectativa de vida da página, que é uma indicação de quantos segundos a página permanecerá no pool.
Por exemplo,
$server = 'hqdbt01'
$counters = @("\Memory\Available MBytes",
"\Memory\Pages/sec",
"\SQLServer:Buffer Manager\Buffer cache hit ratio",
"\SQLServer:Buffer Manager\Lazy writes/sec",
"\SQLServer:Buffer Manager\Page life expectancy"
)
$collections = Get-Counter -ComputerName $server -Counter $counters -SampleInterval 10 -MaxSamples 1
Write-Output $collections
foreach ($collection in $collections)
{$sampling = $collection.CounterSamples | Select-Object -Property TimeStamp, Path, Cookedvalue
$sampling | Format-Table -AutoSize
}
Recomendações e práticas recomendadas
Vejamos agora brevemente as técnicas para dimensionar a memória.
- 1 GB de memória reservado para o sistema operacional
- 1 GB para cada 4 GB de RAM após os 4 GB iniciais, até 16 GB de RAM
- 1 GB cada para cada 8 GB em mais de 16 GB de RAM
Por exemplo, se você tiver um servidor de banco de dados de 32 GB de RAM, a memória a ser fornecida ao sistema operacional seria
- 1 GB, a alocação mínima
- + 3 GB, pois 16 GB – 4 GB =12 GB; 12 GB divididos por 4 GB (cada 4 GB obtém 1 GB) são 3 GB.
- + 2 GB, como 32 GB – 16 GB =16 GB; 16 dividido por 8 (cada 8 GB após 16 GB obtém 1 GB) é 2 GB
Assim, no total, para um servidor com 32 GB de RAM, 7 GB serão reservados para o Sistema Operacional. Esta é a memória máxima alocada para o SQL Server deve ser de 25 GB. Da mesma forma, para um servidor de 64 GB, 10 GB devem ser reservados para o sistema operacional e 54 GB devem ser alocados para o SQL Server.
Todos nós, em algum momento ou outro, ouvimos ou usamos o Windows Management Instrumentation (WMI). Existem várias classes no WMI, que nos permitem extrair informações sobre o hardware, software instalado, sistema operacional ou até mesmo o registro. Podemos até modificar as configurações e realizar ações nesses aspectos.
A classe win32_OperatingSystem é uma classe WMI que possui todas as informações necessárias sobre o ativo sistema operacional (no caso de você ser, digamos, dual boot). Essa classe também pode ser usada para obter a quantidade de memória alocada ao sistema operacional. Aqui estão alguns dos objetos que a classe pode retornar, o que pode nos ajudar (a memória é medida em kilobytes por esta classe):
- TotalVisibleMemorySize :Este campo mostra o total de memória física acessível ao sistema operacional. Blocos de memória inacessíveis podem fazer com que um número menor que o instalado seja exibido aqui.
- FreePhysicalMemory :informa a quantidade de memória física disponível.
- TotalVirtualMemorySize :Esta é a memória virtual total disponível para o sistema operacional usar. Isso inclui a memória física instalada no computador, juntamente com o tamanho do arquivo de paginação.
- FreeVirtualMemory :semelhante ao FreePhysicalMemory, mas também inclui o espaço livre na memória de paginação.
$server='hqdbt01'
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $server | select CSName,
@{name="TotalVirtualMemorySize";expression={($_.TotalVirtualMemorySize/1024).tostring("N0")}},
@{name="TotalVisibleMemorySize";expression={($_.TotalVisibleMemorySize/1024).tostring("N0")}},
@{name="FreePhysicalMemory";expression={($_.FreePhysicalMemory/1024).tostring("N0")}},
@{name="FreeVirtualMemory";expression={($_.FreeVirtualMemory/1024).tostring("N0")}},
@{name="FreeSpaceInPagingFiles";expression={($_.FreeSpaceInPagingFiles/1024).tostring("N0")}},
NumberofProcesses,
NumberOfUsers
Podemos buscar as informações do arquivo de paginação usando a classe WMI Win32_PageFileSetting.
$server='hqdbt01'
Get-WMIObject Win32_PageFileSetting -Computer $server| select @{name="ServerName";expression={$_.__Server}}, Name, InitialSize, MaximumSize
A consulta a seguir fornece os detalhes de uso de memória de alto nível da instância SQL.
SELECT
physical_memory_in_use_kb/1024 Physical_memory_in_use_MB,
large_page_allocations_kb/1024 Large_page_allocations_MB,
locked_page_allocations_kb/1024 Locked_page_allocations_MB,
virtual_address_space_reserved_kb/1024 VAS_reserved_MB,
virtual_address_space_committed_kb/1024 VAS_committed_MB,
virtual_address_space_available_kb/1024 VAS_available_MB,
page_fault_count Page_fault_count,
memory_utilization_percentage Memory_utilization_percentage,
process_physical_memory_low Process_physical_memory_low,
process_virtual_memory_low Process_virtual_memory_low
FROM sys.dm_os_process_memory;
Prepare o roteiro
Vamos integrar as três saídas acima mencionadas em uma única saída de memória:
- Estruturas de memória interna SQL usando contador
- Memória virtual e física disponível usando o objeto WMI
- Configuração do arquivo de paginação usando WMI
A preparação do conteúdo HTML consiste em preencher o valor alimentado da seção diferente do script, entre as tags corretas.
O script pode construir tags HTML válidas. A seguir estão as funções usadas no script.
- writeHTMLHeader:esta função é usada para gerar o cabeçalho e definir o estilo do arquivo HTML.
- writetableFooter:define as tags HTML de fechamento.
- writeTableHeader:define o cabeçalho de saída de treze colunas para o arquivo HTML
- writeMemoryInfo:esta é a função que realiza a fusão das duas saídas da classe WMI. A saída de Win32_PageFileSetting, Win32_OperatingSystem e SMO SQL é passada como argumentos para esta função. Os valores também podem ser transformados ou manipulados nesta seção.
- Seção de e-mail
[expandir título=”Código”]
# First, let’s create a text file, where we will later save memory details $MailServer='mail01.example.com' $MemoryFileName = "f:\PowerSQL\Memory.htm" New-Item -ItemType file $MemoryFileName -Force # Function to write the HTML Header to the file Function writeHtmlHeader { param($fileName) $date = ( get-date ).ToString('yyyy/MM/dd') Add-Content $fileName "<html>" Add-Content $fileName "<head>" Add-Content $fileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>" Add-Content $fileName '<title>SQLShack Memory Usage Report </title>' add-content $fileName '<STYLE TYPE="text/css">' add-content $fileName "<!--" add-content $fileName "td {" add-content $fileName "font-family: Tahoma;" add-content $fileName "font-size: 11px;" add-content $fileName "border-top: 1px solid #999999;" add-content $fileName "border-right: 1px solid #999999;" add-content $fileName "border-bottom: 1px solid #999999;" add-content $fileName "border-left: 1px solid #999999;" add-content $fileName "padding-top: 0px;" add-content $fileName "padding-right: 0px;" add-content $fileName "padding-bottom: 0px;" add-content $fileName "padding-left: 0px;" add-content $fileName "}" add-content $fileName "body {" add-content $fileName "margin-left: 5px;" add-content $fileName "margin-top: 5px;" add-content $fileName "margin-right: 0px;" add-content $fileName "margin-bottom: 10px;" add-content $fileName "" add-content $fileName "table {" add-content $fileName "border: thin solid #000000;" add-content $fileName "}" add-content $fileName "-->" add-content $fileName "</style>" Add-Content $fileName "</head>" Add-Content $fileName "<body>" add-content $fileName "<table width='100%'>" add-content $fileName "<tr bgcolor='#CCCCCC'>" add-content $fileName "<td colspan='13' height='25' align='center'>" add-content $fileName "<font face='tahoma' color='#003399' size='4'><strong>SQLShack Memory Usage Report - $date</strong></font>" add-content $fileName "</td>" add-content $fileName "</tr>" add-content $fileName "</table>" } # Function to write the HTML Header to the file Function writeTableHeader { param($fileName) Add-Content $fileName "<tr bgcolor=#CCCCCC>" Add-Content $fileName "<td width='10%' align='center'>ServerName</td>" Add-Content $fileName "<td width='10%' align='center'>TotalVirtualMemorySize</td>" Add-Content $fileName "<td width='10%' align='center'>TotalVisibleMemorySize</td>" Add-Content $fileName "<td width='10%' align='center'>FreePhysicalMemory</td>" Add-Content $fileName "<td width='10%' align='center'>FreeVirtualMemory</td>" Add-Content $fileName "<td width='10%' align='center'>FreeSpaceInPagingFiles</td>" Add-Content $fileName "<td width='10%' align='center'>NumberofProcesses</td>" Add-Content $fileName "<td width='10%' align='center'>NumberOfUsers</td>" Add-Content $fileName "<td width='10%' align='center'>PageFile</td>" Add-Content $fileName "<td width='10%' align='center'>Page-InitialSize</td>" Add-Content $fileName "<td width='10%' align='center'>Page-MaxSize</td>" Add-Content $fileName "<td width='10%' align='center'>SQLMaxMemory</td>" Add-Content $fileName "<td width='10%' align='center'>SQLMinMemory</td>" Add-Content $fileName "<td width='10%' align='center'>Memory Available MBytes</td>" Add-Content $fileName "<td width='10%' align='center'>Buffer Cache Hit Ratio</td>" Add-Content $fileName "<td width='10%' align='center'>PLE</td>" Add-Content $fileName "</tr>" } Function writeHtmlFooter { param($fileName) Add-Content $fileName "</body>" Add-Content $fileName "</html>" } Function writeMemoryInfo { param($filename,$csname,$TotalVirtualMemorySize,$TotalVisibleMemorySize,$FreePhysicalMemory,$FreeVirtualMemory,$FreeSpaceInPagingFiles,$NumberofProcesses,$NumberOfUsers,$PageFile,$initialSize,$MaxSize,$SQLMaxMemory, $SQLMinMemory ,$mAvailableMBytes, $Buffercachehitratio, $PLE ) Add-Content $fileName "<tr>" Add-Content $fileName "<td>$csname </td>" Add-Content $fileName "<td>$TotalVirtualMemorySize </td>" Add-Content $fileName "<td>$TotalVisibleMemorySize</td>" Add-Content $fileName "<td>$FreePhysicalMemory </td>" Add-Content $fileName "<td>$FreeVirtualMemory </td>" Add-Content $fileName "<td>$FreeSpaceInPagingFiles </td>" Add-Content $fileName "<td>$NumberofProcesses </td>" Add-Content $fileName "<td>$NumberOfUsers</td>" Add-Content $fileName "<td>$PageFile</td>" Add-Content $fileName "<td>$initialSize</td>" Add-Content $fileName "<td>$MaxSize</td>" Add-Content $fileName "<td>$SQLMaxMemory</td>" Add-Content $fileName "<td>$SQLMinMemory</td>" Add-Content $fileName "<td>$mAvailableMBytes</td>" Add-Content $fileName "<td>$Buffercachehitratio</td>" Add-Content $fileName "<td>$PLE</td>" Add-Content $fileName "</tr>" } Function sendEmail { param($from,$to,$subject,$smtphost,$htmlFileName) $body = Get-Content $htmlFileName $body = New-Object System.Net.Mail.MailMessage $from, $to, $subject, $body $body.isBodyhtml = $true $smtpServer = $MailServer $smtp = new-object Net.Mail.SmtpClient($smtpServer) $smtp.Send($body) } writeHtmlHeader $MemoryFileName Add-Content $MemoryFileName "<table width='100%'><tbody>" Add-Content $MemoryFileName "<tr bgcolor='#CCCCCC'>" Add-Content $MemoryFileName "<td width='100%' align='center' colSpan=16><font face='tahoma' color='#003399' size='2'><strong> Memory Usage Details</strong></font></td>" Add-Content $MemoryFileName "</tr>" writeTableHeader $MemoryFileName foreach ($svr in get-content "\\hqdbsp18\f$\PowerSQL\Server.txt"){ $page=Get-WMIObject Win32_PageFileSetting -Computer $svr| select __Server, Name, InitialSize, MaximumSize $dp = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $svr | select CSName, @{name="TotalVirtualMemorySize";expression={($_.TotalVirtualMemorySize/1024).tostring("N0")}}, @{name="TotalVisibleMemorySize";expression={($_.TotalVisibleMemorySize/1024).tostring("N0")}}, @{name="FreePhysicalMemory";expression={($_.FreePhysicalMemory/1024).tostring("N0")}}, @{name="FreeVirtualMemory";expression={($_.FreeVirtualMemory/1024).tostring("N0")}}, @{name="FreeSpaceInPagingFiles";expression={($_.FreeSpaceInPagingFiles/1024).tostring("N0")}}, NumberofProcesses, NumberOfUsers $srv = new-object ('Microsoft.SqlServer.Management.Smo.Server') ($svr) write-host $srv.Configuration.MaxServerMemory.RunValue write-host $srv.Configuration.MinServerMemory.RunValue $counters = @("\Memory\Available MBytes", "\Memory\Pages/sec", "\SQLServer:Buffer Manager\Buffer cache hit ratio", "\SQLServer:Buffer Manager\Lazy writes/sec", "\SQLServer:Buffer Manager\Page life expectancy" ) $collections = Get-Counter -ComputerName $svr -Counter $counters -SampleInterval 5 -MaxSamples 1 Write-Output $collections foreach ($collection in $collections) { $sampling = $collection.CounterSamples | Select-Object -Property TimeStamp, Path, Cookedvalue foreach($sam in $sampling) { if ($sam.Path -like "*\Memory\Available MBytes*") { $mAvailableMBytes=$sam.CookedValue } elseif ($sam.Path -like "*Buffer Manager\Buffer cache hit ratio*") { $Buffercachehitratio=$sam.CookedValue } elseif ($sam.Path -like "*Page life expectancy*") { $PLE=$sam.CookedValue} } } write-host $mAvailableMBytes $Buffercachehitratio $PLE Write-Host $dp.csname $dp.TotalVirtualMemorySize $dp.TotalVisibleMemorySize $dp.FreePhysicalMemory $dp.FreeVirtualMemory $dp.FreeSpaceInPagingFiles $dp.NumberofProcesses $dp.NumberOfUsers $page.InitialSize $page.Name $page.MaximumSize $srv.Configuration.MaxServerMemory.RunValue $srv.Configuration.MinServerMemory.RunValue $mAvailableMBytes $Buffercachehitratio $PLE writeMemoryInfo $MemoryFileName $dp.csname $dp.TotalVirtualMemorySize $dp.TotalVisibleMemorySize $dp.FreePhysicalMemory $dp.FreeVirtualMemory $dp.FreeSpaceInPagingFiles $dp.NumberofProcesses $dp.NumberOfUsers $page.Name $page.InitialSize $page.MaximumSize $srv.Configuration.MaxServerMemory.RunValue $srv.Configuration.MinServerMemory.RunValue $mAvailableMBytes $Buffercachehitratio $PLE } Add-Content $MemoryFileName "</table>" writeHtmlFooter $MemoryFileName $date = ( get-date ).ToString('yyyy/MM/dd') sendEmail [email protected] [email protected] "Memory Usage Report - $Date" $MailServer $MemoryFileName
[/expandir]
Saída
Encerrando
Agora que você aprendeu algumas coisas novas sobre o gerenciamento de memória do SQL Server, você entenderá melhor os recursos do SQL Server.
Se houver RAM adequada no servidor, as páginas de dados podem ter uma vida útil mais longa no buffer pool, o que consequentemente resulta em uma redução drástica nas necessidades de E/S.
Embora na maioria dos casos os Administradores de Banco de Dados dependam das configurações de memória padrão, precisamos entender que os requisitos internos de memória dependem da carga de trabalho da instância.
Este artigo é um passo a passo de alto nível da memória do SQL Server e seus componentes internos. Além disso, abrange os vários motivos por trás dos gargalos de desempenho causados por não definir a memória máxima.
Incluí instruções passo a passo para configurar e configurar um relatório de memória. As etapas sobre como configurar a memória SQL também estão incluídas. Além disso, discutimos vários componentes SQL que contribuem para o uso da memória disponível no ambiente SQL Server.
Um ponto a ser lembrado é que a alocação e desalocação de memória retardam a inicialização. Portanto, se você tiver vários aplicativos parando e iniciando no mesmo servidor, isso poderá afetar o desempenho. Da mesma forma, se houver vários outros aplicativos em execução no mesmo servidor, configurar a memória mínima do servidor e a memória máxima do servidor se torna mais importante para garantir o desempenho ideal.
É tudo por agora…
Referências
- Monitorando o uso da memória
- Importância de definir a memória máxima do servidor no SQL Server e como configurá-la
- Opções de configuração do servidor de memória do servidor