Question

J'ai une base de données PostgreSQL avec une table maître et 2 tables enfants.Ma table maîtresse :

CREATE TABLE test (
    id serial PRIMARY KEY, 
    date timestamp without time zone
);
CREATE INDEX ON test(date);

Mes tables enfant :

CREATE TABLE test_20150812 (
    CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )
) INHERITS (test);

CREATE TABLE test_20150811 (
    CHECK ( date >= DATE '2015-08-11' AND date < DATE '2015-08-12' )
) INHERITS (test);

CREATE INDEX ON test_20150812(date);
CREATE INDEX ON test_20150811(date);

Quand j'exécute une requête comme :

select * from test_20150812 where date > '2015-08-12' order by date desc;

Il revient très rapidement (20-30 millisecondes). EXPLAIN sortir:

 Limit  (cost=0.00..2.69 rows=50 width=212)
   ->  Index Scan Backward using test_20150812_date_idx on test_20150812  (cost=0.00..149538.92 rows=2782286 width=212)
         Index Cond: (date > '2015-08-12 00:00:00'::timestamp without time zone)

Cependant, si j'exécute une requête comme :

select * from test where date > '2015-08-12' order by date desc;

Cela prend beaucoup de temps (10-15 secondes). EXPLAIN sortir:

 Limit  (cost=196687.06..196687.19 rows=50 width=212)
   ->  Sort  (cost=196687.06..203617.51 rows=2772180 width=212)
         Sort Key: public.test.date
         ->  Result  (cost=0.00..104597.24 rows=2772180 width=212)
               ->  Append  (cost=0.00..104597.24 rows=2772180 width=212)
                     ->  Seq Scan on test  (cost=0.00..0.00 rows=1 width=1857)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)
                     ->  Seq Scan on test_20150812 test  (cost=0.00..104597.24 rows=2772179 width=212)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)

constraint_exclusion est réglé sur ON dans mon postgresql.conf.Il ne doit donc être exécuté que le test_20150812.

Je vois que si une requête est exécutée sur la table maître, les index ne sont jamais utilisés.Comment puis-je l’améliorer ?Je souhaite effectuer toutes mes requêtes sur ma table principale.Lors d'une requête pour une date spécifique, je ne m'attends à aucune différence de performances entre les requêtes sur la table principale ou sur la table enfant.

Était-ce utile?

La solution

"date"

N'appelle pas ton timestamp colonne "date", c'est très trompeur.Mieux encore, n'utilisez pas du tout le nom de type de base "date" comme identifiant, car il est sujet aux erreurs, conduit à des messages d'erreur confus et c'est un problème. mot réservé en SQL standard.Cela devrait ressembler à quelque chose comme :

CREATE TABLE test (
  id serial PRIMARY KEY
, ts timestamp NOT NULL  -- also adding NOT NULL constraint
);
CREATE INDEX ON test(ts);

Mises en garde

Soyez conscient de cette mise en garde avec exclusion de contrainte:

L'exclusion de contraintes ne fonctionne que lorsque la requête WHERE la clause contient constantes (ou paramètres fournis en externe).Par exemple, une comparaison avec une fonction non immuable telle que CURRENT_TIMESTAMPne peut pas être optimisé, car le planificateur ne peut pas savoir quelle partition la valeur de la fonction pourrait tomber au moment de l'exécution.

C'est moi qui souligne en gras. Tu as esquivé celui-ci, mais avec votre configuration déroutante, vous pourriez trébucher dessus assez tôt.

Aussi, puisque vous avez tous les jours partitions :

Toutes les contraintes sur toutes les partitions de la table maître sont examinées lors de l'exclusion des contraintes, donc un grand nombre de partitions sont susceptibles d'augmenter considérablement le temps de planification des requêtes.Le partitionnement de l'utilisation de ces techniques fonctionnera bien avec jusqu'à peut-être une centaine de partitions ;n'essayez pas d'utiliser plusieurs milliers de partitions.

C'est moi qui souligne en gras.Si vous travaillez sur plus de quelques mois, essayez plutôt des partitions hebdomadaires ou mensuelles.

Inadéquation dans les prédicats

État de votre chèque :

CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )

Mais votre requête a la condition :

where date > '2015-08-12' order by date desc;  -- should be: >=

Cela laisse un léger décalage (probablement Incorrect!) et force Postgres à revérifier la condition.Pas bien, mais je ne peux pas non plus répondre à votre question.

Utiliser >=, et soit créer la colonne NOT NULL ou ajouter NULLS LAST à la déclaration :

WHERE ts >= '2015-08-12' ORDER BY ts DESC;

...et faites correspondre l'index.

Impur CHECK contrainte

Le CHECK les contraintes sont enregistrées avec date constantes au lieu de timestamp constantes.Cela devrait ressembler à quelque chose comme :

CHECK (ts >= timestamp '2015-08-11' AND ts < timestamp '2015-08-12');

Exclusion de contraintes

Vous écrivez:

constraint_exclusion est réglé sur ON dans mon postgresql.conf.Il ne doit donc être exécuté que le test_20150812.

Comme vous pouvez le voir dans le plan de requête, uniquement test et test_20150812 sont scannés, mais pas test_20150811.Donc :l'exclusion de contrainte fonctionne bien, malgré tous vos écarts.C'est juste une autre fausse piste.

J'ai gagné de nombreuses batailles, mais pas la guerre

Après avoir nettoyé tout ça, je vois un analyse d'index bitmap pour la table enfant au lieu de votre analyse séquentielle.Toujours plus lent qu'une requête sur la table enfant uniquement.Cela est évidemment dû au fait que la table parent elle-même peut également avoir des lignes correspondantes, qui doivent être triées avec le reste, de sorte que le résultat ne peut pas être simplement lu à partir de l'index.

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top