Estou usando o postgres 9.4.
O messages
esquema tem o seguinte: messages pertence a feed_id e postou_at, também as mensagens podem ter uma mensagem pai (no caso de respostas).
Table "public.messages"
Column | Type | Modifiers
------------------------------+-----------------------------+-----------
message_id | character varying(255) | not null
feed_id | integer |
parent_id | character varying(255) |
posted_at | timestamp without time zone |
share_count | integer |
Indexes:
"messages_pkey" PRIMARY KEY, btree (message_id)
"index_messages_on_feed_id_posted_at" btree (feed_id, posted_at DESC NULLS LAST)
Quero retornar todas as mensagens ordenadas por share_count
, mas para cada uma parent_id
, quero retornar apenas uma mensagem. ou seja, se várias mensagens tiverem o mesmo parent_id
, somente a última ( posted_at
) será retornada. O parent_id
pode ser nulo, todas as mensagens com nulo parent_id
devem retornar.
A consulta que usei é:
WITH filtered_messages AS (SELECT *
FROM messages
WHERE feed_id IN (7)
AND (posted_at >= '2015-01-01 04:00:00.000000')
AND (posted_at < '2015-04-28 04:00:00.000000'))
SELECT *
FROM (SELECT DISTINCT ON(COALESCE(parent_id, message_id)) parent_id,
message_id,
posted_at,
share_count
FROM filtered_messages
ORDER BY COALESCE(parent_id, message_id), posted_at DESC NULLS LAST
) messages
ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
Aqui está o http://sqlfiddle.com/#!15/588e5/1/0 , no SQL Fiddle, eu defini o esquema, a consulta exata e o resultado esperado.
Mas o desempenho da consulta é lento quando a tabela de mensagens aumenta. Tentei adicionar vários índices de classificação, mas ele não parece usar o índice. Aqui está a explicação: http://explain.depesz.com/s/Sv2
Como posso criar um índice correto?
fonte
ORDER BY
a subconsulta é totalmente inútil. Além disso, o plano vinculado não pode ser resultado da consulta lançada - não há mençãometadata
, por exemplo.feed_id
eposted_at
você não mencionoumetadata
nada, o que parece ser do tipo JSON? Repare sua pergunta para torná-la consistente. Você seleciona> 500k linhas na CTE ... Quantas linhas estão na tabela? Qual porcentagem de linhas você normalmente seleciona na CTE? Qual a porcentagem de linhasparent_id IS NULL
? Considere as informações na tag [postgresql-performance] para perguntas sobre desempenho.parent_id
? (min / avg / max)metadata
. Atualmente, a tabela de mensagens possui 10 mil dados, mas aumenta rapidamente. Eu acho que para separar em tabelas de partição para cada feed_id. Como estou buscando apenas por ID do feed. a porcentagem de parent_id null vs not null é de cerca de 60% / 40%. uma busca típica é de cerca de 1-2% da tabela. (em torno de 100 mil mensagens) O desempenho para 100 mil é de cerca de 1s, mas quando chega a 500 mil +, ele usa o índice de bitmap e normalmente leva 10 segundos.Respostas:
Inquerir
Esta consulta deve ser substancialmente mais rápida em qualquer caso:
O CTE não faz nada aqui que uma subconsulta simples também não possa fornecer. E um CTE introduz uma barreira de otimização, pois é executado separadamente e seu resultado é materializado.
Você tem mais um nível de subconsulta do que realmente precisa.
A expressão
(COALESCE(parent_id, message_id)
não é compatível com um índice simples, você precisaria de um índice nessa expressão. Mas isso também pode não ser muito útil, dependendo da distribuição dos dados. Siga meus links abaixo para obter informações detalhadas.Dividir o caso simples de
parent_id IS NULL
um em separadoSELECT
pode ou não oferecer o melhor. Especialmente, se esse for um caso raro de qualquer maneira, nesse caso, uma consulta combinada com um índice ativado(COALESCE(parent_id, message_id)
poderá ter um desempenho melhor. Outras considerações se aplicam ...Índices
Especialmente quando suportado com estes índices:
Os dois índices parciais cobrem a tabela inteira juntos e têm o mesmo tamanho juntos que um único índice total.
As duas últimas colunas
parent_id, message_id
só fazem sentido se você conseguir verificações somente de índice . Caso contrário, remova-os dos dois índices.SQL Fiddle.
Dependendo dos detalhes ausentes,
DISTINCT ON
pode ou não ser a melhor técnica de consulta para esse fim. Leia aqui a explicação detalhada:E alternativas possivelmente mais rápidas aqui:
fonte