Vous n'êtes pas identifié(e).
Pages : 1
- Ce qui me chiffonne c'est que les VACUUM ANALYSE sont effectués régulièrement sur mes tables par l'autovacuum.
Question bête : les VACUUM ANALYSE lancés par l'autovacuum sont-ils moins "performants" ? Comprendre : agissent-ils différent que ceux lancés manuellement ?
- J'ai l'impression que ma structure FSM est adaptée à mes besoins :
max_fsm_pages = 800000
max_fsm_relations = 1000
Résultat final d'un VACUUM ANALYSE sur l'ensemble de mes données :
INFO: la structure FSM contient 54193 pages dans 89 relations
DETAIL: Un total de 55248 emplacements de pages est utilisé (ceci incluant la
surcharge).
55248 emplacements de pages sont requis pour tracer tout l'espace libre.
Les limites actuelles sont : 800000 emplacements de pages, 1000 relations,
utilisant 4752 Ko.
VACUUM
- Pour en revenir au VACUUM FULL, quelles sont ces "très mauvaises requêtes" qui mettraient en défaut une maintenance bien faite ?
La suppression de 10% d'enregistrements sur une table de plus d'un million par exemple ?
Merci Marc pour ces propositions.
Monter default_statistics_target à 100 ne change rien à mon problème.
Par contre, l'index composé (account_id, state) le résoud (j'ai laissé default_statistics_target à 100, je peux éventuellement essayer de le repasser à 10).
En parallèle, j'ai effectué un VACUUM FULL (hier je me suis contenté d'un ANALYZE) sur ma seconde machine sans ajouter l'index composé et j'obtiens également des performances satisfaisantes.
2 questions me viennent à l'esprit :
- Si je comprends bien l'index sur state me dessert plus qu'autre chose dans ce cas précis, car comme vous le dites PostgreSQL fait le mauvais paris. Simple curiosité, existe-t'il d'autre moyens que l'index composé pour "forcer" l'utilisation d'un index plutôt qu'un autre ? Parce que je m'attendais naturellement à ce qu'il utilise l'index sur account_id, puis state...
- Le démon autovacuum passe régulièrement sur toutes mes tables, je pensais ne plus avoir besoin de VACUUM FULL... Est-ce qu'effectuer régulièrement un VACUUM FULL est une bonne pratique ? Ou alors cela résulte d'une mauvaise configuration ?
Bonjour,
Je n'arrive pas à expliquer une importante différence de performance sur une requête simple, en fonction de l'évolution du seul paramètre "account_id" :
SELECT * FROM listings_5
WHERE account_id = 981
ORDER BY state ASC
LIMIT 50 OFFSET 0
"listings_5" est une table enfant de "listings". Le découpage est effectuée en fonction de la valeur d'un champ "store_id".
Les colonnes "account_id", "state" et "store_id" sont indexées.
Lorsque je lance la requête ci-dessus directement sur la table "listings_5" pour account_id = 981, j'obtiens ceci :
(la table contient 154 461 enregistrements pour le compte 981)
Limit (cost=0.00..684.02 rows=50 width=1452) (actual time=238.055..2027.142 rows=50 loops=1)
-> Index Scan using listings_5_state_idx on listings_5 (cost=0.00..1960460.66 rows=143305 width=1452) (actual time=238.053..2027.093 rows=50 loops=1)
Filter: (account_id = 981)
Total runtime: 2027.265 ms
Pour account_id = 1699 :
(alors que la table ne contient aucun enregistrement pour le compte 1699)
Limit (cost=0.00..17029.71 rows=50 width=1452) (actual time=95497.761..95497.761 rows=0 loops=1)
-> Index Scan using listings_5_state_idx on listings_5 (cost=0.00..1960460.66 rows=5756 width=1452) (actual time=95497.759..95497.759 rows=0 loops=1)
Filter: (account_id = 1699)
Total runtime: 95497.856 ms
En exécutant ces requêtes l'une après l'autre à plusieurs reprises, j'obtiens à peu près le même résultat.
J'ai effectué un VACUUM ANALYSE sur toutes les tables, j'ai redémarré la base, j'ai réindexé les tables listings, sans succès.
De plus je ne constate pas cette différence sur ma seconde machine de test, même matériel, même config, mais qui contient une version plus récente de ma base de prod (donc plus lourde).
Autres précisions :
- Si j'effectue la même requête sur la table mère, en précisant store_id = 5, la tendance s'inverse... (instantané pour 1699, quelques secondes pour 981)
- Si je supprime le critère de tri, le temps de réponse est "normal"...
- Si j'ajoute un critère de tri final (listing_id, la clé primaire), le temps de réponse est "normal" également... (instantané pour 1699, quelques secondes pour 981) :
SELECT * FROM listings_5
WHERE account_id = 1699
ORDER BY state ASC, listing_id
LIMIT 50 OFFSET 0
-------
Limit (cost=19855.16..19855.28 rows=50 width=1468) (actual time=0.015..0.015 rows=0 loops=1)
-> Sort (cost=19855.16..19869.84 rows=5872 width=1468) (actual time=0.014..0.014 rows=0 loops=1)
Sort Key: state, listing_id
Sort Method: quicksort Memory: 17kB
-> Index Scan using listings_ebay_account_idx on listings_ebay (cost=0.00..19660.09 rows=5872 width=1468) (actual time=0.008..0.008 rows=0 loops=1)
Index Cond: (account_id = 1699)
Total runtime: 0.149 ms
Bref, je vous avoue que je suis un peu perdu. Je ne sais pas quelle démarche effectuer pour traquer le problème.
C'est pourquoi je fais appel à vous...
Merci pour tout élément de réponse !
La contrib ltree peut également être digne d'intérêt : http://docs.postgresql.fr/8.3/ltree.html
Bonjour,
Cette solution fonctionne, mais je trouve peu élégant de surcharger les valeurs des colonnes price_ht et price_ttc de la table commande.
Mais bon, si c'est le seul moyen d'assurer la cohérence des données, et étant donné qu'il y aura très peu de mises à jour des prix sur ces tables, je pense que cette solution sera validée et exploitée très bientôt.
OK merci. Voici un aperçu du code résultant :
Table commande
CREATE OR REPLACE FUNCTION commande_before_update() RETURNS TRIGGER AS $$
BEGIN
IF OLD.price_ht <> NEW.price_ht OR OLD.price_ttc <> NEW.price_ttc
THEN
SELECT INTO NEW.price_ht, NEW.price_ttc
COALESCE(sum(price_ht), 0) AS price_ht, COALESCE(sum(price_ttc), 0) AS price_ttc
FROM produit WHERE commande_id = OLD.commande_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Table Produit
CREATE OR REPLACE FUNCTION produit_after_update() RETURNS TRIGGER AS $$
BEGIN
IF OLD.commande_id <> NEW.commande_id
THEN
UPDATE commande SET
price_ht = price_ht - OLD.price_ht,
price_ttc = price_ttc - OLD.price_ttc
WHERE commande_id = OLD.commande_id;
UPDATE commande SET
price_ht = price_ht + NEW.price_ht,
price_ttc = price_ttc + NEW.price_ttc
WHERE commande_id = NEW.commande_id;
ELSIF OLD.price_ht <> NEW.price_ht OR OLD.price_ttc <> NEW.price_ttc
THEN
UPDATE commande SET
price_ht = price_ht - OLD.price_ht + NEW.price_ht,
price_ttc = price_ttc - OLD.price_ttc + NEW.price_ttc
WHERE commande_id = OLD.commande_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Bonjour,
J'ai 2 tables, "commande" et "produit". Une commande est liée à 1..n produit(s).
J'ai ajouté une colonne "prix" à "commande", somme des prix des produits associés, calculé automatiquement par trigger.
Je souhaite maintenant que ce champ "prix" soit en lecture seule. J'ai donc ajouté un trigger sur la table "commande" pour empêcher tout UPDATE.
Le problème est que je souhaiterais quand même laisser passer l'UPDATE provenant du trigger sur la table "produit"...
Est-il possible de détecter l'origine d'un UPDATE et d'agir en conséquence ?
Merci,
Julien
Pages : 1