Pergunta

Estou tentando encontrar uma maneira direta de melhorar o desempenho de fóruns muito ativos, onde há um grande número de postagens e o MySQL não consegue mais classificar tabelas na memória e não parece aproveitar ao máximo os índices.

Esta consulta simples encontra a postagem mais recente em cada tópico para um usuário determinar se ele tem alguma resposta desde então (comparando posteriormente o topic_time)

SELECT p.*, MAX(post_time) as post_time FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
LIMIT 50

mesa simples e plana se parece com

post_id | poster_id | topic_id | post_status | post_time | post_text

No entanto, seu desempenho cai quando há um milhão de postagens e o próprio usuário tem dezenas de milhares de postagens.O MySQL não consegue mais classificar a tabela na memória ou há muitas linhas para verificar.Pode levar até 3 segundos no uso no mundo real, o que é inaceitável porque está aumentando a CPU durante esse tempo e deixando todos os outros mais lentos.

Posso fazer qualquer combinação de índice, é claro, mas o mysql parece gostar principalmente de usar uma combinação de

poster_id + post_time 

Portanto, ele apenas seleciona as 50 mil postagens de um usuário entre um milhão e começa a agrupar por topic_id e classificar.Estranhamente, adicionar topic_id ao mix de índices não parece ajudar no desempenho, embora possa ser a ordem dos campos de índice.

Tentei escrever um JOIN equivalente para poder usar mais de um índice, mas tive problemas com o fato de que cada lado precisa ser filtrado por post_status e poster.

Eu estava pensando que seria mais rápido, pelo menos nas primeiras páginas, se o mysql pudesse ser feito para PRIMEIRO classificar os dados através de seu índice por post_time e então começar a escolher o topic_id distinto para o usuário em ordem decrescente.Acho que isso exigiria uma subconsulta e não tenho certeza se uma subconsulta de resultado de 50k seria melhor, ainda precisa de uma tabela temporária.

É claro que uma solução fundamental seria aumentar o design principal para que houvesse outra tabela que apenas armazenasse o post_time máximo para cada usuário em cada tópico, mas isso é uma mudança muito grande, a menos que nenhuma outra solução possa ser encontrada.

Obrigado por qualquer sugestão!


adicionando um exemplo do mundo real e EXPLAIN:

registro lento

# Query_time: 2.751334  Lock_time: 0.000056 Rows_sent: 40  Rows_examined: 48286
SELECT   p.*, MAX(post_time) as post_time FROM forum_posts AS p   WHERE p.poster_id = '2' AND p.post_status = '0' GROUP BY p.topic_id  ORDER BY post_time DESC LIMIT 7000, 40;

explicar

select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
SIMPLE          p   ref poster_time poster_time 4   const   27072   Using where; Using temporary; Using filesort
Foi útil?

Solução

Primeiro, corrija sua consulta para fornecer resultados determinados:

SELECT p.topic_id, 
       MAX(post_time) as post_time 
FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
  LIMIT 50 ;

Então tente depois de adicionar um índice em (post_status, poster_id, topic_id, post_time).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top