J'ai une structure de table partitionnée comme:
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);
....
Etc. Chaque table a des rangées d'environ 20 m.
Si j'existais pour un échantillon de capteurs et un échantillon d'horodatages dans la clause WHERE
, le plan de requête indique les tables correctes sélectionnées et les index étant utilisés par E.G.:
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' ;
Cependant, si j'utilise un CTE, ou mettez les valeurs horodatées dans une table (non représentée, même avec des index sur la table temporaire).
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)
)
Quelque chose comme le bas
SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts
Effectue une analyse d'index sur chaque table. Ce qui est encore relativement rapide, mais avec une complexité croissante de requêtes, cela peut transformer en SEQ SCAN qui finira par être très lent pour récupérer ~ 40k rangs d'un sous-ensemble limité de tables partitionnées (4-5 sur 50).
Je crains que quelque chose comme ceci est le problème.
Pour les expressions non triviales, vous devez répéter la condition plus ou moins de verbatim dans les requêtes pour que le planificateur de requête Postgres doit comprendre qu'il peut compter sur la contrainte de contrôle. Même s'il semble redondant!
Comment puis-je améliorer la structure de partitionnement et de la requête pour réduire la probabilité d'exécuter SEQ SCAN sur toutes mes données?
L'exclusion basée sur les contraintes [CBE] est effectuée au stade précoce de la planification de la requête, juste après l'analyse de la requête, mappée sur les relations réelles et réécrites. ( Internals , planificateur/optimiseur Stage)
Le planificateur ne peut assumer aucun contenu de la table "sensor_sample".
Donc, à moins que vous ayez des valeurs codées dans la requête, le planificateur n'exclurea pas les "partitions".
Je suppose que ce qui se passe avec la variante CTE ... le planificateur est restreint car vous utilisez des tablesample et que toute la sous-requête peut être traitée comme volatille, même si les littéraux dans la sous-requête sont statiques. ( C'est juste ma supposition, je ne suis pas expert sur le code planificateur )
Du côté lumineux, l'analyse d'index avec résultat négatif est floue rapidement. (Scannez à la page unique au plus!) Donc, à moins que vous n'ayez plus de 10000 partitions, je ne me dérangerais pas.
Donc, pour répondre directement à votre question:
Vous ne pouvez pas améliorer la structure de cette structure de données.
Considère les analyses d'index - elles sont bon marché;
En ce qui concerne les analyses séquentielles - elles sont évitées dans la mesure du possible, comme vous le voyez sur vos propres exemples.