ID da causa db-no-index · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de banco de dados (Equipe de infraestrutura)
Sem índice, para achar as linhas que atendem à condição é preciso ler a tabela inteira (full scan).
Por quê O deploy de um recurso novo adiciona uma busca por uma condição sem índice → Efeito Milhões de linhas são varridas, e uma única query leva de centenas de ms a alguns segundos → Na tela Atraso para carregar a caixa de correio e o histórico de trocas; as conexões ficam presas e outras requisições também esperam
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de banco de dados (Equipe de infraestrutura)
O que fazer (Equipe de desenvolvimento)
Revisar o plano de execução das queries novas antes do deploy, adicionar índices, verificar se as queries que alteram dados (UPDATE, DELETE) também usam índice.
O que fazer (Equipe de infraestrutura)
Monitorar o log de queries lentas, encontrar as queries com full scan e compartilhar com a equipe de desenvolvimento, criar índices em produção pelo método online, que segura lock por pouco tempo.
Números de referência
Com índice, alguns ms; sem índice, a query fica mais lenta em proporção ao volume de dados e, em tabelas grandes, chega a ser de centenas a dezenas de milhares de vezes mais lenta.
No gráfico
Degrau a partir de um momento · Latência das queries do BD, linhas lidas
Onde olhar
No MySQL, ver Rows_examined e Rows_sent no slow query log (com log_queries_not_using_indexes ativado, ele também registra queries que não usam índice) e SUM_NO_INDEX_USED e SUM_ROWS_EXAMINED em events_statements_summary_by_digest do performance_schema, e rodar EXPLAIN. No PostgreSQL, ver seq_scan e seq_tup_read em pg_stat_user_tables e rodar EXPLAIN
Confirma se
Uma query que apareceu depois do deploy lê milhares de vezes mais linhas (Rows_examined) do que retorna (Rows_sent), e o EXPLAIN mostra varredura da tabela inteira (MySQL type ALL, PostgreSQL Seq Scan). O seq_tup_read de uma tabela grande cresce rápido a partir do horário do deploy
Descarta se
Usa índice e mesmo assim está lenta: espera por lock (db-hot-row, db-ddl-lock) ou mudança no plano de execução (db-plan-flip). Full scan em tabela pequena pode ser normal
Como verificar
Ferramentas de infra (sem precisar do código do jogo)
Saiba mais
Não são só as leituras que ficam lentas. Dependendo do BD, queries que alteram dados sem índice (UPDATE, DELETE) põem lock até nas linhas varridas e podem bloquear o salvamento de jogadores que não têm nada a ver com elas.
Fontes
How MySQL Uses IndexesMySQL Sem índice, o banco lê a tabela inteira a partir da primeira linha, e quanto maior a tabela, maior o custo
Locks Set by Different SQL Statements in InnoDBMySQL Se não houver índice adequado e a tabela inteira for varrida, todas as linhas recebem lock e até inserções de outros usuários ficam bloqueadas
The Slow Query LogMySQL Registra as queries que passam do long_query_time (padrão de 10 segundos); também é possível registrar à parte as queries que não usam índice
CREATE INDEX (PostgreSQL Documentation)PostgreSQL Com CONCURRENTLY, o índice é criado sem bloquear escritas; a criação normal bloqueia escritas até terminar
Statement Summary TablesMySQL events_statements_summary_by_digest: por formato de query, SUM_NO_INDEX_USED (vezes em que rodou sem índice) e SUM_ROWS_EXAMINED
EXPLAIN Output FormatMySQL type ALL indica varredura da tabela inteira, que em geral se evita adicionando um índice