Restrição de partição não usada para junções envolvendo tabelas particionadas por carimbo de data / hora

11

Eu tenho uma estrutura de tabela particionada como:

CREATE TABLE measurements (
    sensor_id bigint,
    tx timestamp,
    measurement int
);

CREATE TABLE measurements_201201(
    CHECK (tx >= '2012-01-01 00:00:00'::timestamp without time zone 
       AND tx < ('2012-01-01 00:00:00'::timestamp without time zone + '1 mon'::interval))    
)INHERITS (measurements);
CREATE INDEX ON measurements_201201(sensor_id);
CREATE INDEX ON measurements_201201(tx);
CREATE INDEX ON measurements_201201(sensor_id, tx);
....

E assim por diante. Cada tabela possui aproximadamente 20 milhões de linhas.

Se eu consultar uma amostra de sensores e uma amostra de registros de data e hora na WHEREcláusula, o plano de consulta mostrará as tabelas corretas sendo selecionadas e os índices sendo usados, por exemplo:

SELECT *
FROM measurements
INNER JOIN sensors TABLESAMPLE BERNOULLI (0.01) USING (sensor_id)
WHERE tx BETWEEN '2015-01-04 05:00' AND '2015-01-04 06:00' 
    OR tx BETWEEN '2015-02-04 05:00' AND '2015-02-04 06:00' 
    OR tx BETWEEN '2014-03-05 05:00' AND '2014-04-07 06:00' ;

No entanto, se eu usar um CTE ou colocar os valores de carimbo de data / hora em uma tabela (não mostrados, mesmo com índices na tabela temporária).

WITH sensor_sample AS(
    SELECT sensor_id, start_ts, end_ts
    FROM sensors TABLESAMPLE BERNOULLI (0.01)
    CROSS JOIN (VALUES (TIMESTAMP '2015-01-04 05:00', TIMESTAMP '2015-01-04 06:00'),
        (TIMESTAMP '2015-02-04 05:00', TIMESTAMP '2015-02-04 06:00'),
        (TIMESTAMP  '2014-03-05 05:00', '2014-04-07 06:00') ) tstamps(start_ts, end_ts)
)

Algo como o abaixo

SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts

Executa uma verificação de índice em todas as tabelas. O que ainda é relativamente rápido, mas com a crescente complexidade das consultas, isso pode se transformar em verificações seq, que acabam sendo muito lentas para recuperar ~ 40K linhas de um subconjunto limitado de tabelas particionadas (4-5 de 50).

Eu estou preocupado que algo como este é o problema.

Para expressões não triviais, é necessário repetir a condição mais ou menos detalhada nas consultas para fazer com que o planejador de consultas do Postgres entenda que ele pode confiar na restrição CHECK. Mesmo que pareça redundante!

Como posso melhorar a estrutura de particionamento e consulta para reduzir a probabilidade de executar varreduras seq em todos os meus dados?

raphael
fonte
1
grande questão - mas seria ainda melhor se você colar resultados de EXPLAIN (ANALISAR, BUFFERS)
filiprem

Respostas:

1

A exclusão baseada em restrições [CBE] é realizada no estágio inicial do planejamento da consulta, logo após a consulta ser analisada, mapeada para relações reais e reescrita. ( internos , estágio Planejador / Otimizador)

O planejador não pode assumir nenhum conteúdo da tabela "sensor_sample".

Portanto, a menos que você tenha valores codificados na consulta, o planejador não excluirá "partições".

Eu acho que o que acontece com a variante CTE ... o planejador é restrito porque você usa TABLESAMPLE e toda a subconsulta pode ser tratada como volátil, mesmo que os literais na subconsulta sejam estáticos. ( esse é apenas o meu palpite, não sou especialista em código de planejador )

Pelo lado positivo, a varredura de índice com resultado negativo é incrivelmente rápida. (digitalização de página única, no máximo!), a menos que você tenha mais de 10000 partições, eu não me incomodaria.

Então, para responder sua pergunta diretamente:

  • Você não pode melhorar muito mais essa estrutura de dados.

  • Veja as verificações de índice - elas são baratas;

  • Em relação às verificações sequenciais - elas são evitadas quando possível, como você vê em seus próprios exemplos.

filiprem
fonte