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 comprend environ 20 millions de lignes.
Si je demande un échantillon de capteurs et un échantillon d'horodatages dans la WHERE
clause, le plan de requête montre les bonnes tables sélectionnées et les index utilisés, par exemple:
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 que je mets les valeurs d'horodatage dans une table (non affichées, 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 ci-dessous
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 la complexité croissante des requêtes, cela peut se transformer en analyses séquentielles qui finiront par être très lentes pour récupérer ~ 40K lignes à partir d'un sous-ensemble limité de tables partitionnées (4-5 sur 50).
Je crains que quelque chose comme ça soit le problème.
Pour les expressions non triviales, vous devez répéter la condition plus ou moins verbatim dans les requêtes pour que le planificateur de requêtes Postgres comprenne qu'il peut s'appuyer sur la contrainte CHECK. Même si cela semble redondant!
Comment puis-je améliorer le partitionnement et la structure des requêtes pour réduire la probabilité d'exécuter des analyses seq sur toutes mes données?
Réponses:
L'exclusion basée sur les contraintes [CBE] est effectuée à un stade précoce de la planification de la requête, juste après l'analyse de la requête, sa mise en correspondance avec les relations réelles et sa réécriture. ( internes , étape Planner / Optimizer)
Le planificateur ne peut assumer aucun contenu de la table "sensor_sample".
Donc, sauf si vous avez des valeurs codées en dur dans la requête, le planificateur n'exclura pas les "partitions".
Je suppose que ce qui se passe avec la variante CTE ... le planificateur est restreint car vous utilisez TABLESAMPLE et toute la sous-requête peut être traitée comme volatile même si les littéraux de la sous-requête sont statiques. ( c'est juste ma supposition, je ne suis pas expert en code de planificateur )
Du côté positif, le balayage d'index avec un résultat négatif est incroyablement rapide. (numérisation d'une seule page au maximum!) donc à moins que vous ayez plus de 10000 partitions, je ne m'embêterais pas.
Donc, pour répondre directement à votre question:
Vous ne pouvez pas améliorer beaucoup plus cette structure de données.
Analyses d'index Regardin - elles sont bon marché;
Concernant les analyses séquentielles - elles sont évitées lorsque cela est possible, comme vous le voyez sur vos propres exemples.
la source