Eu tenho esta tabela no PostgreSQL 9.4:
CREATE TABLE user_operations(
id SERIAL PRIMARY KEY,
operation_id integer,
user_id integer )
A tabela consiste em ~1000-2000
diferentes operações, cada uma correspondendo a algum subconjunto (consistindo aproximadamente de 80000-120000
elementos cada) do conjunto S
de todos os usuários:
S = {1, 2, 3, ... , 122655}
Parâmetros:
work_mem = 128MB
table_size = 880MB
Eu também tenho um índice no arquivo operation_id
.
PERGUNTA: Qual seria o plano ideal para consultar todos os distintosuser_id
para uma parte significativa dooperation_id
conjunto (20%-60%) como:
SELECT DISTINCT user_id FROM user_operation WHERE operation_id < 500
É possível criar mais índices na tabela . Atualmente, o plano para a consulta é:
HashAggregate (cost=196173.56..196347.14 rows=17358 width=4) (actual time=1227.408..1359.947 rows=598336 loops=1)
-> Bitmap Heap Scan on user_operation (cost=46392.24..189978.17 rows=2478155 width=4) (actual time=233.163..611.182 rows=2518122 loops=1)
Recheck Cond: (operation_id < 500)
-> Bitmap Index Scan on idx (cost=0.00..45772.70 rows=2478155 width=0) (actual time=230.432..230.432 rows=2518122 loops=1)
Index Cond: (operation_id < 500)
Esse plano de consulta é realmente ideal nessas circunstâncias? Quero dizer, não tenho certeza sobre a correção de usar Bitmap Heap Scan
. Eu apreciarei todas as referências a artigos relevantes.
Use uma consulta recursiva:
Em combinação com um índice nas colunas nessa ordem
(user_id, operation_id)
. Espero varreduras de índice que filtrem na segunda coluna. Estatísticas de tabela razoavelmente precisas são importantes, então o Postgres sabe que só terá que pular algumas linhas no índice para encontrar a próxima . Geralmente, pode -se querer aumentar a meta de estatísticas em particular para:user_id
operation_id
Como existem apenas
~1000-2000 different operations
, isso pode nem ser necessário, mas é um pequeno preço a pagar.Detalhes:
Se o predicado
operation_id < 500
for estável (sempre o mesmo), torne-o um índice parcial apenas(user_id)
:Então as estatísticas
operation_id
não são mais relevantes para esta consulta.Mesmo que o predicado não seja estável, pode haver maneiras de otimizar - dependendo de toda a gama de condições possíveis e frequências de valor.
O desempenho deve ser... delicioso .
Eu otimizei a técnica nesta resposta relacionada no SO (com explicação detalhada):
Se você tiver uma
users
tabela separada e uma grande parte de todos os usuários puder ser encontrada em sua amostra, estilos de consulta ainda mais rápidos serão possíveis. Detalhes na resposta vinculada.