Explorando o parâmetro 'max worker threads' no SQL Server

Neste vamos dissecar o parâmetro max worker threads do SQL Server, veremos o papel desse parâmetro na arquitetura de execução, os valores padrão conforme o número de CPUs lógicas, quando faz sentido ajustá-lo e diferenças entre edições Standard vs. Enterprise. Vou utilizar exemplos práticos para consulta e alteração, e dicas de monitoramento/diagnóstico (DMVs e wait stats). Vamos lá!

O que é o parâmetro max worker threads?

O max worker threads é uma opção de configuração avançada do SQL Server que define o número máximo de threads (worker threads) disponíveis globalmente no SQL Server para processar requisições – como consultas, logins, logouts e outras solicitações de aplicação. Em termos simples, ele controla o tamanho do pool de threads que o SQL Server pode usar para executar tarefas concorrentes. Cada worker thread corresponde basicamente a um thread do sistema operacional que o SQL Server utiliza para dar suporte às sessões de cliente e execução de comandos. Faz parte da arquitetura schedulers (agendador) do SQLOS – o SQL Server inicia um agendador por núcleo lógico disponível, e aloca threads de trabalho para realizar as tarefas atribuídas a esses agendadores.

Por padrão, o valor de max worker threads é 0, o que não significa zero threads – na verdade, 0 indica que o SQL Server deve configurar automaticamente o número apropriado de threads de trabalho, de acordo com a quantidade de CPUs e a arquitetura do sistema. Essa configuração automática geralmente é ótima para a maioria dos sistemas, garantindo um balanceamento entre atender muitas conexões e não sobrecarregar o servidor. A ideia é que o SQL Server mantém um pool de threads e reutiliza-os (thread pooling) para evitar o custo de criar/destruir threads para cada requisição. Assim, centenas ou milhares de conexões podem ser atendidas sem precisar ter um thread dedicado para cada uma simultaneamente, economizando recursos.

Quando o número de solicitações ativas excede o número de threads disponíveis (ou seja, todos os workers estão ocupados), as novas tarefas esperam em fila até que um thread fique livre. Nesse caso, você poderá observar o wait type THREADPOOL nas estatísticas de espera – esse é um indicador de que faltam threads livres para iniciar novas requisições. Enquanto espera THREADPOOL, para o usuário parece que o SQL Server “congelou” ou não está respondendo, pois não consegue agendar a execução dessas novas tarefas por falta de workers. Esse comportamento não é um bug, mas pode ser indesejável em certos cenários críticos. Veremos adiante como monitorar isso e possíveis ajustes.

Valores padrão e configuração automática por CPU

Como mencionado, com max worker threads = 0 o SQL Server calcula automaticamente o tamanho do pool de threads com base no número de processadores lógicos disponíveis. Há um mínimo de 512 threads garantido em sistemas 64-bit, mesmo em servidores com poucas CPUs. Para além disso, a Microsoft define uma fórmula para o cálculo:

  • Até 4 CPUs lógicas: usa 512 threads (valor mínimo)

  • Entre 5 e 64 CPUs lógicas: usa 512 + 16 * (Nº CPUs - 4) threads

  • Acima de 64 CPUs lógicas: usa 512 + 32 * (Nº CPUs - 4) threads

Em outras palavras, o crescimento padrão é de 16 threads adicionais por CPU lógica extra (além de 4) até 64 CPUs; e para servidores grandes com mais de 64 CPUs, o incremento é de 32 threads por CPU extra. Alguns exemplos de configuração padrão em máquinas 64-bit ilustram isso:

  • 4 CPUs lógicas (ou menos): 512 threads (mínimo)

  • 8 CPUs lógicas: 576 threads

  • 16 CPUs lógicas: 704 threads

  • 64 CPUs lógicas: 1472 threads

  • 256 CPUs lógicas: 8576 threads

Perceba que até 4 CPUs o valor permanece 512, e depois cresce linearmente conforme as fórmulas acima. Esse ajuste automático procura atribuir mais threads a servidores com mais CPUs, permitindo maior potencial de concorrência conforme o hardware escala. Não existe um “número mágico” fixo de threads ideal para todo SQL Server – a configuração ótima é aquela padrão (auto) na maioria dos casos, já que ela leva em conta o tamanho do servidor.

Importante: Vale frisar que o max worker threads limita apenas threads de trabalho para requisições de usuário. O SQL Server internamente ainda pode criar threads de sistema fora desse pool para certas funções críticas (Lazy Writer, Checkpoint, Log Writer, alguns threads de Availability Groups, etc.), então o número total de threads no processo pode exceder o valor configurado – mas os threads além do limite serão apenas esses internos, não threads de execução de consultas de usuário.

Quando faz sentido alterar o valor de max worker threads?

Em geral, a recomendação dos especialistas e da Microsoft é não alterar esse parâmetro e mantê-lo em 0 (auto), a menos que você tenha evidências claras de que a mudança é necessária. A maioria dos ambientes funciona melhor com o ajuste automático. Muitas vezes, problemas de performance são causados por outras razões (consultas longas, bloqueios, gargalos de I/O, etc.) e não por falta de threads em si. Ajustar o número de threads sem analisar a causa raiz pode mascarar sintomas e até piorar a situação.

Cenários em que considerar a alteração: Dito isso, há situações incomuns em que aumentar o max worker threads manualmente pode ser válido (geralmente de forma temporária). Por exemplo, quando existem Muitos bancos em Availability Groups (AG), Cada banco de dados consome threads mesmo ociosos, para sincronia. Em um servidor primário com centenas de bancos em AG, esses threads “reservados” podem consumir grande parte do pool.

Outro cenário possível é quando o servidor realmente precisa atender milhares de sessões ativas simultâneas por design (por exemplo, um servidor OLTP com 2000 conexões concorrentes fazendo trabalho significativo). Nesse caso extremo, mesmo sem usar recursos especiais, o default (por exemplo, ~512 threads em máquina pequena) poderia se mostrar insuficiente, causando filas. Aumentar o max worker threads proporcionaria mais “tickets” (threads) para que todas as requisições iniciem sua execução em vez de ficarem esperando thread livre. Mas atenção, se você chegou ao ponto de esgotar threads, deve também avaliar a arquitetura ou carga de trabalho – simplesmente liberar mais threads não aumenta o poder de processamento do CPU, pode apenas adiar ou redistribuir o problema.

Quando não faz sentido alterar: Se o gargalo não for claramente a falta de threads, você provavelmente não verá ganho mudando este parâmetro. Por exemplo, se os threads estão ocupados devido a consultas lentas (CPU-bound ou I/O-bound), adicionar mais threads não acelerará essas consultas – pelo contrário, pode saturar ainda mais a CPU ou o subsistema de I/O. Nesses casos, é melhor otimizar as consultas, índices ou hardware ao invés de mexer no pool de threads.

Standard vs. Enterprise: diferenças de comportamento

Uma dúvida comum é se a edição do SQL Server (Standard vs. Enterprise) afeta o comportamento do max worker threads. O próprio mecanismo de thread pooling e agendamento é igual nas duas edições – ambas utilizam schedulers por CPU lógica e aplicam a mesma fórmula de cálculo de threads. Porém, a diferença está no limite de recursos de cada edição: o SQL Server Standard tem restrições no uso de CPU que indiretamente limitam o max worker threads efetivo.

No SQL Server 2022 Standard a instância pode usar no máximo 24 núcleos ou 4 soquetes, o que for menor. Isso significa que se o servidor físico tiver, digamos, 64 CPUs lógicas, a edição Standard ainda só vai utilizar 24 delas. O cálculo automático de threads considera apenas os núcleos que a edição consegue usar. Assim, mesmo com 64 CPUs presentes, o Standard configuraria por padrão algo em torno de 832 threads (baseado em 24 núcleos suportados, não em 64). Já a edição Enterprise não possui esse limite de CPU (usa todos os núcleos disponíveis até o máximo do SO) – numa máquina de 64 CPUs, a Enterprise configuraria ~1472 threads pelo cálculo padrão, aproveitando todos os cores, e em 128 CPUs configuraria ~4480 threads.

Verificando e alterando o valor via T-SQL (sp_configure)

O parâmetro max worker threads é uma configuração de servidor. Podemos consultar seu valor atual e modificá-lo usando o comando T-SQL sp_configure (lembrando de habilitar opções avançadas, já que este é um parâmetro avançado). A alteração não requer restart do serviço – entra em vigor imediatamente após um RECONFIGURE. Abaixo estão exemplos:

-- Verificar o valor atual do max worker threads:
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;  -- habilita ver opções avançadas

EXEC sp_configure 'max worker threads';

Ao executar o sp_configure acima, o SQL Server retornará as colunas config_value (valor configurado) e run_value (valor em execução atualmente) para o parâmetro. Por padrão, deve aparecer 0 se ninguém alterou. Você também pode conferir o número efetivo de threads calculado rodando a query:

SELECT max_workers_count 
FROM sys.dm_os_sys_info;

Essa DMV sys.dm_os_sys_info expõe o valor máximo de threads em uso atualmente pela instância (já considerando cálculo automático ou qualquer configuração manual). Assim, é útil para confirmar o número real de threads que o SQL Server está usando como limite no momento.

Para alterar o parâmetro, utilizamos novamente sp_configure passando o novo valor e depois RECONFIGURE. Exemplo, para ajustar o máximo de threads para 1024:

-- Exemplo: alterando max worker threads para 1024
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'max worker threads', 1024;
RECONFIGURE;

Dicas de monitoramento e diagnóstico de threads

Para DBAs, é fundamental monitorar o uso de worker threads e identificar sinais de exaustão do pool antes que se tornem um problema grave. Aqui estão algumas dicas e consultas úteis:

  • Contador de Threads Ativos vs Máximo: Você pode acompanhar quantos threads estão em uso no momento em comparação ao limite. A DMV sys.dm_os_workers lista todos os workers atualmente existentes, e sys.dm_os_sys_info dá o total máximo. Uma consulta simples para ver threads usados vs. disponíveis é:
SELECT (SELECT max_workers_count FROM sys.dm_os_sys_info) AS [MaxThreads],
COUNT(*) AS [ThreadsEmUso]
FROM sys.dm_os_workers;

Se ThreadsEmUso estiver frequentemente muito próximo de MaxThreads, é um sinal de que seu servidor está chegando no limite de workers.

  • Verificar tarefas esperando por thread: A DMV sys.dm_os_schedulers possui colunas work_queue_count (tarefas em fila aguardando thread) e runnable_tasks_count (tarefas aguardando CPU nos schedulers ativos). Em um sistema saudável, normalmente work_queue_count fica zero na maior parte do tempo, se for > 0 consistentemente, significa tem workload pronto mas não havia thread disponível para executar, indicando forte possibilidade de saturação de threads. Você pode examinar a fila de threads por scheduler assim:
SELECT scheduler_id, work_queue_count, runnable_tasks_count
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE';

Se algum scheduler mostra work_queue_count alto, possivelmente atingimos o limite de threads naquele momento. Já um runnable_tasks_count alto com work_queue_count baixo sugere CPU ocupada/demorada (as tasks estão esperando CPU, não thread).

  • Contagem consolidada de threads e filas: Juntando as informações acima, uma consulta prática é somar os workers ativos e tarefas em espera em todos schedulers, para ter um panorama geral:
SELECT (SELECT max_workers_count FROM sys.dm_os_sys_info) AS TotalThreads,
SUM(active_workers_count) AS ThreadsEmUso,
SUM(work_queue_count) AS TarefasEsperandoThread,
SUM(runnable_tasks_count) AS TarefasEsperandoCPU
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE';

Essa query mostra quantos threads ativos existem no momento e quantas tarefas estão pendentes esperando thread ou CPU. Se TarefasEsperandoThread for maior que zero regularmente, é indicativo de esgotamento do pool de threads (THREADPOOL). Já TarefasEsperandoCPU > 0 com ThreadsEmUso próximo do limite indica que mesmo com thread alocado as tasks aguardam tempo de CPU – típico de CPU saturada.

  • Wait Stats – THREADPOOL: Sempre monitore as estatísticas de espera globais via sys.dm_os_wait_stats, com consulta focada no wait type THREADPOOL :
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type = 'THREADPOOL';

Se waiting_tasks_count e o tempo de espera para THREADPOOL estiverem crescendo, definitivamente houve momentos em que faltaram threads. Compare esse valor em relação a outras waits – se THREADPOOL aparece entre as maiores waits, é um alarme vermelho de thread pool exausto.

  • Sessões pendentes no scheduler: Em uma emergência (SQL aparentemente travado por falta de threads), você pode usar a Conexão de Administrador Dedicada (DAC) para conectar e diagnosticar. A DAC permite uma conexão mesmo com o servidor sob stress. Com ela, consultas às DMVs acima podem confirmar se há muitas tarefas em work_queue (esperando thread). A partir daí, a ação imediata pode ser matar alguma sessão longa para liberar um thread (via KILL <SPID>). Esse procedimento foi mencionado pela Microsoft como forma de recuperar um SQL que pareça não responder devido a todas threads ocupadas. Após estabilizar, deve-se planejar soluções de longo prazo (otimizar consultas ou aumentar max threads se for caso recorrente).

Em suma, utilize as DMVs (sys.dm_os_workers, sys.dm_os_schedulers, sys.dm_os_sys_info, sys.dm_os_wait_stats) regularmente ou configure alertas no seu monitoramento para detectar sinais de thread pool stress. Um padrão a se observar é a presença de wait THREADPOOL concomitante com CPU não totalmente usada – isso normalmente denuncia threads esgotadas. Já CPU 100% com muitos runnable tasks indica falta de CPU (não necessariamente de threads). Saber diferenciar ajuda a decidir se o ajuste de max worker threads é pertinente ou não.

Conclusão

O parâmetro max worker threads é um componente crítico da arquitetura do SQL Server que raramente precisa de ajuste manual. Ele define quantas “linhas de frente” de execução o SQL Server terá para servir as requisições, mas aumentar esse exército nem sempre traz vitória – muitas vezes, a estratégia (plano de consulta, índice, hardware adequado) importa mais que o número de threads. Ajuste-o somente com base em evidências sólidas e compreensão dos trade-offs, conforme discutimos.

Fui, mas volto com mais SQL Server em breve!

✍️ Sobre o autor
O Prof. Landry é especialista em Microsoft SQL Server desde 1999, Microsoft Trainer, Professor Universitário e criador do canal SQL Server Expert no YouTube, com conteúdo técnico semanal para DBAs e profissionais de dados.

🚀 Quer aprender mais sobre SQL Server?
👉 Me acompanhe no LinkedIn e inscreva-se no canal para não perder nenhuma dica prática!

0
Subscribe to my newsletter

Read articles from SQL Server Expert directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

SQL Server Expert
SQL Server Expert

O Prof. Landry Duailibe é especialista em Microsoft SQL Server desde 1999, Microsoft Certified Trainer, professor universitário e criador do canal SQL Server Expert no YouTube, onde compartilha conteúdo técnico semanal para DBAs e profissionais de dados. Já ajudou milhares de alunos a evoluírem suas habilidades com SQL Server e conquistarem melhores oportunidades na área de dados.