En utilisant PostgreSQL 9.2, j'ai des problèmes avec les requêtes lentes sur une table relativement grande (200+ millions de lignes). Je n'essaie rien de fou, j'ajoute juste des valeurs historiques. Vous trouverez ci-dessous la requête et la sortie du plan de requête.
Ma disposition de table:
Table "public.energy_energyentry"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('energy_energyentry_id_seq'::regclass)
prop_id | integer | not null
timestamp | timestamp with time zone | not null
value | double precision | not null
Indexes:
"energy_energyentry_pkey" PRIMARY KEY, btree (id)
"energy_energyentry_prop_id" btree (prop_id)
"energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
"energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED
Les données varient du 01/01/2012 à aujourd'hui, avec de nouvelles données constamment ajoutées. Il y a environ 2,2k valeurs distinctes dans le prop_id
clé étrangère, répartie uniformément.
Je remarque que les estimations de ligne ne sont pas loin, mais les estimations de coût semblent plus grandes d'un facteur 4x. Ce n'est probablement pas un problème, mais est-ce que je pourrais y faire quelque chose?
J'espère que l'accès au disque pourrait être le problème, car la table n'est pas en mémoire tout le temps.
EXPLAIN ANALYZE
SELECT SUM("value")
FROM "energy_energyentry"
WHERE
"prop_id"=82411
AND "timestamp">'2014-06-11'
AND "timestamp"<'2014-11-11'
;
Aggregate (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1) -> Index Scan using energy_energyentry_prop_id_timestamp_idx on energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1) Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone)) Total runtime: 51504.841 ms
Des suggestions sur la façon d'accélérer cela?
Je suis aussi très bien d'entendre que je n'ai rien fait de bizarre.
Votre table est grande , tout comme tout index couvrant toute la table. En admettant que:
timestamp = now()
) sont entréesJe suggérerais un index partiel, multi-colonnes (couvrant!) :
CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0'; -- adapt to your needs
N'incluez que la plage de temps qui est interrogée régulièrement. L'efficacité se détériore avec le temps avec de nouvelles entrées. Recréez l'index de temps en temps. (Vous devrez peut-être adapter vos requêtes.) Voir la réponse liée ci-dessous.
La dernière valeur de colonne n'est incluse que pour obtenir analyses d'index uniquement de cela. Un réglage agressif du vide automatique peut aider en gardant la carte de visibilité à jour, comme @jjanes déjà mentionné .
L'index partiel devrait tenir dans RAM plus facilement et y rester plus longtemps.
Vous devrez peut-être inclure cette condition WHERE
dans les requêtes pour que le planificateur comprenne que l'index est applicable à la requête, comme:
SELECT sum(value) AS sum_value
FROM energy_energyentry
WHERE prop_id = 82411
AND "timestamp" > '2014-06-11 0:0'
AND "timestamp" < '2014-11-11 0:0'
AND "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed
Étant donné que votre requête résume un grand nombre de lignes (rows=13578
), cela va prendre un certain temps, même avec un scan indexé uniquement. Cependant, cela ne devrait pas être proche de 50 secondes. Moins d'une seconde sur tout matériel à moitié décent.
En relation (mais ignorez CLUSTER
et FILLFACTOR
, les deux ne sont pas pertinents si vous pouvez obtenir des analyses d'index uniquement):
À part:
Puisque vous actuellement avez un index sur (prop_id, "timestamp")
, l'index supplémentaire sur seulement (prop_id)
peut coûter plus cher que ça ne vaut:
Si vous activez l'index (prop_id, "timestamp", "value"), il pourrait utiliser une analyse d'index uniquement pour calculer la valeur sans jamais visiter la table. Cela pourrait économiser beaucoup d'accès aléatoire au disque.
Pour tirer le meilleur parti, vous devez être agressif à propos de l'aspiration de la table. Les paramètres autovac par défaut ne sont pas suffisamment agressifs pour les tables d'insertion uniquement sur lesquelles vous souhaitez prendre en charge efficacement les analyses d'index uniquement.