Como diagnosticar uma consulta SQL lenta específica no banco do seu servidor de MU Online
Encontre e corrija a query específica que está travando o banco de dados do seu servidor de MU Online, usando plano de execução, índices e o Profiler/Extended Events do SQL Server.
Um servidor de MU Online pode ter GameServer e ConnectServer perfeitamente saudáveis e mesmo assim sofrer travamentos visíveis para o jogador — login demorado, ranking que trava ao abrir, guild list lenta — porque uma única query SQL mal otimizada está monopolizando o banco de dados. Diferente de um
Um servidor de MU Online pode ter GameServer e ConnectServer perfeitamente saudáveis e mesmo assim sofrer travamentos visíveis para o jogador — login demorado, ranking que trava ao abrir, guild list lenta — porque uma única query SQL mal otimizada está monopolizando o banco de dados. Diferente de um problema de infraestrutura genérico, esse tipo de gargalo é cirúrgico: uma consulta específica, rodando com frequência, sem o índice certo. Este tutorial ensina a identificar exatamente qual query é a culpada, entender por que ela é lenta e corrigi-la sem quebrar o resto do sistema.
Sintomas típicos de uma query lenta específica
O primeiro sinal de que o problema é uma query pontual (e não o servidor de banco inteiro) é a localização do sintoma: uma ação específica do jogo trava (abrir ranking, entrar no jogo, listar guild, processar trade) enquanto o resto continua fluido. Se tudo está lento ao mesmo tempo, o problema tende a ser recursos gerais (CPU, disco, memória do SQL Server); se uma ação trava e as outras seguem normais, o problema é uma query específica competindo por recursos ou travada em um lock.
Ferramentas de diagnóstico disponíveis
| Ferramenta | Uso | Quando usar |
|---|---|---|
| SQL Server Profiler | Captura queries em tempo real com duração | Diagnóstico pontual, ambiente de teste |
| Extended Events | Substituto moderno do Profiler, mais leve | Produção, captura contínua sem impacto grande |
| Activity Monitor | Visão rápida de sessões ativas e esperas | Primeira olhada durante o incidente |
DMVs (sys.dm_exec_query_stats) | Estatísticas agregadas de queries desde o último restart | Achar a query mais custosa historicamente |
| Plano de execução (Execution Plan) | Mostra como o SQL Server decidiu buscar os dados | Depois de identificar a query candidata |
Passo 1 — Capturar a query no momento do sintoma
Com o Extended Events (recomendado em produção por ter overhead menor que o Profiler clássico), crie uma sessão filtrando por duração mínima:
CREATE EVENT SESSION [SlowQueries] ON SERVER
ADD EVENT sqlserver.sql_statement_completed(
ACTION(sqlserver.sql_text, sqlserver.client_hostname)
WHERE duration > 1000000 -- 1 segundo, em microssegundos
)
ADD TARGET package0.event_file(SET filename = N'SlowQueries.xel');
GO
ALTER EVENT SESSION [SlowQueries] ON SERVER STATE = START;
Reproduza o sintoma no jogo (abra o ranking, faça login) e depois pare a sessão para analisar o arquivo .xel no SQL Server Management Studio.
Passo 2 — Achar a query mais custosa historicamente
Se o sintoma é intermitente e você não conseguiu capturar ao vivo, use as DMVs de estatísticas acumuladas:
SELECT TOP 20
qs.total_elapsed_time / qs.execution_count AS avg_time_us,
qs.execution_count,
SUBSTRING(qt.text, qs.statement_start_offset/2 + 1,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(max), qt.text)) * 2
ELSE qs.statement_end_offset END - qs.statement_start_offset)/2 + 1) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
ORDER BY avg_time_us DESC;
Essa query ordena pelo tempo médio de execução — a candidata número 1 quase sempre é a mesma query que o jogador reclama estar travando.
Passo 3 — Ler o plano de execução
Com a query identificada, peça o plano de execução real (Include Actual Execution Plan no SSMS) e procure sinais de alerta:
| Elemento no plano | O que significa | Ação |
|---|---|---|
| Table Scan em tabela grande | Não há índice sendo usado | Criar índice na coluna do WHERE/JOIN |
| Index Scan (não Seek) | Índice existe mas não é seletivo o suficiente | Revisar colunas do índice |
| Ícone de warning amarelo | Estimativa de linhas muito diferente do real | Atualizar estatísticas (UPDATE STATISTICS) |
| Key Lookup repetido | Índice cobre o filtro mas não as colunas retornadas | Criar índice coberto (INCLUDE) |
| Sort com custo alto | ORDER BY sem índice que já entregue a ordem | Índice na coluna de ordenação |
Passo 4 — Casos clássicos no banco de MU Online
Alguns padrões se repetem em praticamente todo emulador (IGCN, MuEMU, X-Team):
- Ranking geral (
SELECT TOP N ... ORDER BY Resets DESC): sem índice na coluna de Resets/level, o SQL Server varre a tabela de personagens inteira a cada abertura de ranking. Índice na coluna de ordenação resolve na maioria dos casos. - Login (
SELECT * FROM MEMB_INFO WHERE memb___id = @id): deveria ser instantâneo; se está lento, geralmente falta índice (ou até chave primária) na coluna de login, ou a tabela está com fragmentação alta. - Guild list / guild member: joins entre tabela de guild e de personagem sem índice na chave estrangeira geram Table Scan duplo.
- Log de trade/chat: tabelas de log crescem indefinidamente; sem índice e sem rotina de limpeza, queries que consultam histórico recente ficam cada vez mais lentas com o tempo.
Passo 5 — Criar o índice certo
Depois de identificar a coluna candidata, crie um índice não-clusterizado direcionado:
CREATE NONCLUSTERED INDEX IX_Character_Resets
ON Character (ResetCount DESC)
INCLUDE (CharacterName, Level, Class);
O INCLUDE evita o "Key Lookup" ao já entregar as colunas que a query pede no SELECT, sem precisar que elas façam parte da chave de ordenação do índice.
Passo 6 — Validar o ganho
Rode a query novamente com SET STATISTICS TIME ON e SET STATISTICS IO ON antes e depois de criar o índice, comparando logical reads e tempo de CPU. Uma melhora real costuma reduzir logical reads em uma ordem de grandeza (de milhares para dezenas), não apenas alguns milissegundos.
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- rodar a query aqui
Parâmetro sniffing: quando a mesma query varia de rápida para lenta
Se a query às vezes é rápida e às vezes lenta com dados parecidos, o problema pode ser plano de execução reutilizado para um parâmetro atípico (parameter sniffing). Sintomas: primeira execução do dia lenta, depois rápida, ou o oposto. Soluções comuns: OPTION (RECOMPILE) na query específica (custo de CPU extra por execução, mas plano sempre adequado), ou reescrever a procedure com variáveis locais para forçar um plano mais genérico.
Manutenção preventiva de índices e estatísticas
Índices se fragmentam com o tempo (INSERT/UPDATE/DELETE constantes de um jogo online geram isso rapidamente). Agende manutenção periódica:
-- Rebuild em índices com fragmentação alta (>30%)
ALTER INDEX ALL ON Character REBUILD;
-- Atualizar estatísticas para o otimizador ter dados corretos
UPDATE STATISTICS Character;
Rode isso em janela de baixo movimento (madrugada), nunca em horário de pico — um rebuild consome I/O e pode competir com o próprio jogo pelos mesmos recursos.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Ranking demora vários segundos para abrir | Falta de índice na coluna de ordenação | Criar índice não-clusterizado com INCLUDE |
| Login lento só para alguns jogadores | Fragmentação alta na tabela de conta | Rebuild de índice e checar chave de busca do login |
| Query rápida e lenta alternadamente | Parameter sniffing | OPTION (RECOMPILE) ou reescrever com variável local |
| Tudo lento ao mesmo tempo, não só uma ação | Problema de recurso geral, não de query | Verificar CPU/disco/memória do servidor de banco |
| Performance piora com o tempo, sem mudança de código | Log/histórico crescendo sem limpeza nem índice | Criar rotina de arquivamento/purga e índice na coluna de data |
Checklist de diagnóstico de query lenta
- Sintoma localizado em uma ação específica do jogo, não no servidor todo.
- Extended Events ou DMV usado para capturar a query exata.
- Plano de execução analisado em busca de Table/Index Scan.
- Índice criado nas colunas de filtro/ordenação identificadas.
- Ganho validado com
STATISTICS IO/TIMEantes e depois. - Parameter sniffing descartado ou tratado se a lentidão for intermitente.
- Rotina de manutenção de índice/estatística agendada para madrugada.
Depois de resolver a query pontual, vale revisar a saúde geral do banco e do GameServer como um todo para evitar que o próximo gargalo passe despercebido — o tutorial de criação de servidor de MU Online cobre a configuração de base que sustenta esse tipo de manutenção.
Perguntas frequentes
Como sei que o problema é uma query e não o servidor de banco em geral?
Se a CPU/disco do servidor de banco está normal mas um comando específico do jogo trava (login lento, ranking demorando, trade travando), o problema é localizado. Rode o Activity Monitor ou Extended Events durante o sintoma para isolar a query exata antes de mexer em hardware.
Preciso saber SQL avançado para usar o plano de execução?
O básico já ajuda muito: procure ícones de warning (amarelo) no plano gráfico e operadores como Table Scan/Index Scan em tabelas grandes — eles quase sempre indicam falta de índice. Você não precisa dominar tudo para resolver os casos mais comuns.
Criar um índice novo tem algum risco?
Sim. Índices aceleram leitura mas custam em escrita (todo INSERT/UPDATE precisa atualizar o índice também) e ocupam espaço em disco. Em tabelas de alta escrita, como logs de conexão, avalie o trade-off antes de criar índices em excesso.
O que é um parâmetro sniffing e por que ele deixa a query lenta às vezes?
É quando o SQL Server reutiliza um plano de execução otimizado para um valor de parâmetro específico, mas esse plano é ruim para outros valores. A query 'às vezes' fica rápida e 'às vezes' lenta com os mesmos dados, o que confunde o diagnóstico se você não souber procurar por isso.
Rebuild de índice resolve lentidão automaticamente?
Ajuda quando a causa é fragmentação, mas não resolve queries mal escritas ou ausência de índice adequado. Rode o rebuild como manutenção periódica, não como solução mágica para todo problema de performance.