PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 Re : Réplication » Mise à jour d'un cluster postgresql utilisant la réplication synchrone » 15/04/2024 15:34:31

Il n' a pas 36 solutions.

Soit :

1) pg_dump + pg_restore avec reconstruction des réplicats.
2) pg_upgrade cf https://docs.postgresql.fr/14/pgupgrade.html
3) dupliquer votre infrastructure avec des serveurs pg16, et mettre en place une réplication logique du master pg15 vers le master pg16.

#2 Général » Récupérer les DELETE d'une réplication logique » 15/04/2024 10:22:55

herve.lefebvre
Réponses : 0

Bonjour,

Existerait-il un moyen de récupérer les ordres DELETE qui proviennent d'une publication ?

Je voudrais tracer les suppression sur des tables d'une base de données ; mais comme la base est déjà surchargée on voudrait supprimer les triggers qui servent à ça.

L'idée est donc de mettre les tables à tracer dans une publication pour delete, mais :

- on ne peut pas faire de réplication logique vers des vues (même avec un trigger INSTEAD OF DELETE).
- Il faut absolument que la clef soit présente dans la table destination, sinon il est impossible de récuérer cette clef dans le trigger sur la table destination (j'ai tenté de surcharger le type BIGINT en redéfinissant l'opérateur "=" pour qu'il soit toujours vrai, le trigger sur DELETE se déclenche bien, mais impossible de récupérer la valeur de la clef).

Est-ce qu'il y aurait un moyen de tracker les ordres delete qui sont adressés à une souscription ?

#4 Re : Général » Errer le caractère dans l'encodage UTF8 pas d'équivalent dans WIN1252 » 22/03/2024 18:36:47

Hello,

mourad a écrit :

je rencontre cette erreur le caractère dont la séquence d'octets dans l'encodage « UTF8 » n'a pas d'équivalent dans l'encodage « WIN1252 »


C'est une erreur de la DB ou bien de l'application ? Vous avez accès au code source de l'application ?

Le QString travaille en UNICODE sur tous les O/S. Après si l'erreur est produite par l'application, il est possible que dans le code source de l'appli il soit fait appel à QString.toLocal8Bit() auquel cas, il n'y a pas grand chose à faire : Soit recompiler/exécuter l'appli sous Linux, soit remplacer les appels QString.toLocal8Bit() par des appels QString.toUtf8()

Si l'appli exporte les QString en Utf8, il faut bien sûr migrer la DB en UTF8.

#5 Re : Général » Solution pour versionner le code plpgsql » 15/03/2024 14:24:04

Non, AMHA il ne faut pas créer un projet spécifique, il faut créer une arborescence "SGBD" spécifique dans le projet existant.
Cela permet de "tagger" les scripts de fonctions / DDL du SGBD de la même façon que le reste du projet (web services etc.) afin de gérer les compatibilités et adhérences ( Appli V1 / Base V1 ; Appli V2 / Base V2 etc.)

#6 Re : Général » Solution pour versionner le code plpgsql » 15/03/2024 11:14:52

En général, on scripte la création des fonctions. On fait des fichiers  un fichier .sql pour chaque fonction qui en comporte la définition, un script shell qui va exécuter tous ces .sql ; et tout ça est mis dans le GIT.

#7 Re : Général » psql reconnais ou pas le mot de passe..... (PG16 Windows) » 13/01/2024 21:54:40

C'est peut-être un problème IPv4/IPv6 ...

Genre dans le pg_hba.conf il y a une autorisation de connexion pour "localhost" 127.0.0.1 (ipV4) ; mais pas pour "::1" (localhost en ipV6)

Essayez pour voir :

C:\Program Files\PostgreSQL\16\bin>psql.exe -h 127.0.0.1 -p 5433 -U postgresql

#8 Re : Général » psql reconnais ou pas le mot de passe..... (PG16 Windows) » 13/01/2024 21:52:53

C'est peut-être un problème IPv4/IPv6 ...

Genre dans le pg_hba.conf il y a une autorisation de connexion pour "localhost" 127.0.0.1 (ipV4) ; mais pas pour "::1" (localhost en ipV6)

#9 Re : Installation » [RESOLU]Nouvelle installation postgresql 16.1 / Windows10 » 08/01/2024 19:24:24

joshw a écrit :

J'ai beaucoup à apprendre... merci pour ces précisions ! Peut-être que je veux aller trop vite...

Ça va, un CREATE DATABASE c'est un bon point de départ ;-)

#12 Re : Général » Segmentation fault » 20/09/2023 16:19:36

Commencer par désactiver le JIT. Nous avons eu aussi du SEGV, c'était lié au jit.

#13 Re : Général » Migration directory PGSQL » 28/08/2023 18:25:00

LiamS a écrit :

Bonjour,
Auriez-vous par contre une commande qui permet de faire une sauvegarde de la base de donnée ? (pas trop envie de tout reperdre la prochaine fois que ça tombera)
Cdt

Si la base a une taille "raisonnable" (chez nous on compte < 200 Go), le plus simple est de faire un pg_dump la nuit.

#14 Optimisation » Index BRIN » 25/08/2023 18:30:45

herve.lefebvre
Réponses : 2

Bonjour,

Il y a quelque chose qui me laisse perplexe, c'est la non utilisation de l'index BRIN sur un max() :

aegir=# select version();
                                                               version                                                                
--------------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 14.9 (Ubuntu 14.9-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
(1 row)
aegir=# create table example (id bigint);
CREATE TABLE
aegir=# create index brin_example on example  using brin(id);
CREATE INDEX
aegir=# insert into example ( select generate_series(1,1000000));
INSERT 0 1000000
aegir=# select pg_size_pretty(pg_relation_size('example'));
 pg_size_pretty 
----------------
 35 MB
(1 row)

aegir=# select pg_size_pretty(pg_relation_size('brin_example'));
 pg_size_pretty 
----------------
 24 kB
(1 row)
aegir=# explain (analyze, verbose) select max(id) from example;
                                                                   QUERY PLAN                                                                    
-------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=10633.55..10633.56 rows=1 width=8) (actual time=80.798..90.351 rows=1 loops=1)
   Output: max(id)
   ->  Gather  (cost=10633.33..10633.54 rows=2 width=8) (actual time=80.732..90.344 rows=3 loops=1)
         Output: (PARTIAL max(id))
         Workers Planned: 2
         Workers Launched: 2
         ->  Partial Aggregate  (cost=9633.33..9633.34 rows=1 width=8) (actual time=55.675..55.676 rows=1 loops=3)
               Output: PARTIAL max(id)
               Worker 0:  actual time=43.249..43.250 rows=1 loops=1
               Worker 1:  actual time=43.237..43.238 rows=1 loops=1
               ->  Parallel Seq Scan on public.example  (cost=0.00..8591.67 rows=416667 width=8) (actual time=0.009..26.193 rows=333333 loops=3)
                     Output: id
                     Worker 0:  actual time=0.011..20.722 rows=251488 loops=1
                     Worker 1:  actual time=0.011..20.815 rows=251764 loops=1
 Planning Time: 0.192 ms
 Execution Time: 90.382 ms
(16 rows)

Pourquoi diable le BRIN n'est pas utilisé ? Je pensais qu'il suffisait de faire le max de toutes les bornes supérieures pour avoir le max() non ?


Évidemment, avec un index btree, l'index est bien utilisé :

aegir=# create index bt_example on example(id);
CREATE INDEX
aegir=# explain (analyze, verbose) select max(id) from example;
                                                                           QUERY PLAN                                                                            
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.45..0.46 rows=1 width=8) (actual time=0.026..0.027 rows=1 loops=1)
   Output: $0
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.42..0.45 rows=1 width=8) (actual time=0.024..0.025 rows=1 loops=1)
           Output: example.id
           ->  Index Only Scan Backward using bt_example on public.example  (cost=0.42..28480.42 rows=1000000 width=8) (actual time=0.023..0.024 rows=1 loops=1)
                 Output: example.id
                 Index Cond: (example.id IS NOT NULL)
                 Heap Fetches: 0
 Planning Time: 0.165 ms
 Execution Time: 0.039 ms
(11 rows)

Il y a quelque chose qui m'échappe au sujet des BRIN ?

#15 Re : Optimisation » Fragmentation des tables et indexes » 31/07/2023 09:19:26

dev.isc84 a écrit :

Bonjour

Merci Mortimer et Guillaume pour ce post très intéressant, à partir de quel PCT_DEAD_LINE nous devons faire un vacuum full ?

Bonne journée

Normalement, on ne fait jamais de vacuum full.

S'il y en a besoin c'est que l'autovacuum et/ou les batches de vacuum sont mal tunés.

#16 Général » Paramètres de session & monitoring » 03/07/2023 16:12:11

herve.lefebvre
Réponses : 1

Bonjour,

Est-ce qu'il est possible de voir les les paramètres de session d'une requête dans pg_stat_activity

(genre voir si la requête tourne avec  un  SET ENABLE_SEQSCAN TO OFF;)

#18 Re : Optimisation » querying partioned table does not use the partition key when joining » 04/04/2023 19:45:18

etienne_lq a écrit :

L'ajout ou non d'une clé étrangère entre les tables ne change pas ce comportement.

Je déconseille fortement l'utilisation de clés étrangères sur les tables partitionnées PostgreSQL.

D'abord parce qu'un simple ATTACH peut prendre des heures, voire des jours selon la volumétrie et rendre la table inexploitable pendant ce temps (exclusive shared lock).

Ensuite, il y a manifestement des bugs sur les FK de tables partitionnées lors des ATTACH/DETACH(*)  qui AMHA ne seront pas résolus de sitôt(**).

Au boulot, en solution de contournement en attendant mieux, on fait une vérification d'intégrité avant de faire le ATTACH ; et on remplace la FK par un trigger "maison" qui fait le check d'intégrité lors des insert/update.

(*) Ref: https://www.postgresql.org/message-id/C … .gmail.com
(**) Ref : https://www.postgresql.org/message-id/C … .gmail.com

#19 Re : Optimisation » querying partioned table does not use the partition key when joining » 04/04/2023 19:18:51

etienne_lq a écrit :

Merci pour vos réponses:
@herve:

select n_live_tup,n_dead_tup from pg_stat_user_tables where relname like 'table_part_%';
relname     |n_live_tup|n_dead_tup|
------------+----------+----------+
table_part_1|         0|         0|
table_part_2|         0|         0|
table_part_3|         0|         0|

Si je comprends bien cela signifie que toutes les partitions sont a priori équivalentes c'est bien cela ? (j'ai rentré la même quantité de données dans chacune: 10k lignes), ce qui explique les plans d'execution.

Oui, mais à ce que je comprends, il n'y a jamais eu de VACUUM ANALYZE effectué (j'ai pas vérifié, mais je pense que cela devrait figurer dans les stats des partitions), par conséquent un scan de l'index entraînera forcément une lecture de la page de données pointée par les feuilles de l'index, donc autant effactuer directement un Seq Scan sur les pages de données.

Effectuez un VACUUM ANALYZE sur la table, et refaites un EXPLAIN ANALYZE histoire de voir si le plan d'exécution change.

#20 Re : Optimisation » querying partioned table does not use the partition key when joining » 30/03/2023 15:51:13

etienne_lq a écrit :

Bonjour,

Merci pour la réponse et désolé pour le post en anglais.
Quant au problème j'ai essayé d'ajouter une foreign key mais cela ne change rien.
Ce que je ne comprends pas c'est pourquoi la première requête a besoin de scan toutes les partitions alors que la clé de partition est fournie implicitement via la jointure, j'aimerais savoir comment mieux écrire mes requêtes pour éviter ce comportement.


Bonjour.

Vous avez dans votre table_ref des valeurs qui 'pointent' sur les 3 partitions, donc de toute façon, il devra aller chercher dans les 3 partitions.

ça vous donne quoi :

select pg_relation_size(relname::text) from pg_stat_user_tables where relname like 'table_part_%';

et

select n_live_tup,n_dead_tup from pg_stat_user_tables where relname like 'table_part_%';

??

#21 Re : Général » Temps de restauration pgBackRest » 25/03/2023 16:36:25

Pour ceux que cela intéresse, un backup pgbackrest "full" qui prend ~ 14 heures, est restauré en en peu moins de 10 heures.

#22 Re : Général » Nombre important de fichiers » 16/03/2023 13:00:14

$ cat /etc/mke2fs.conf
[defaults]
        base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr
        default_mntopts = acl,user_xattr
        enable_periodic_fsck = 0
        blocksize = 4096
        inode_size = 256
        inode_ratio = 16384

... 

Indique que par défaut, un boc d'inodes de 256 octets sera écrit par mkfs pour 16384 octets formattés.

Le nombre d'inodes peut être spécifié directement avec l'option -N lors du mkfs. (Ne pas oublier qu'un fichier, selon sa taille, peut prendre plusieurs inodes).

Le nombre d'inodes présents, utilisés et libres peut être vérifié avec "df -i".

#23 Re : Général » Nombre important de fichiers » 15/03/2023 16:53:24

Euh, je ne connais pas vraiment de limite au nombre de fichiers.
Il y a une limite au nombre de fichiers ouverts simultanément oui.
Il y a aussi une limite au nombre de fichiers liée au nombre d'inodes qui a été défini lors de la création du filesystem.

Pour vos problèmes avec "tar" je suspecte que le problème n'est pas le nombre de fichiers, mais l'utilisation d'un jocker ("*") dans un répertoire qui a genre plusieurs milliers de fichiers,  qui lorsqu'il est interprété remplit le buffer de noms de fichiers.

#24 Re : Général » monitoring erreur vacuum » 14/03/2023 14:13:48

DBA95 a écrit :

Bonjour,

Quels sont les codes retour lors d'erreurs pouvant survenir lors d'un vacuum ?
L'objectif est de superviser cette tâche.

Merci

Cordialement

Dba95

Vous pouvez superviser les timestamps last_vacuum et last_analyze de la table pg_stat_user_tables pour vérifier la date où le VACUUM/ANALYZE s'est terminé pour la dernière fois

#25 Re : Migration » [Résolu] problème requête après migration de MariaDB vers postgresql » 10/03/2023 16:32:08

PEREZ J. a écrit :

Je pense comprendre ce que tu veux faire avec le where mais je ne vois pas comment ça peut fonctionner.
Pour tester, j'ai utilisé une requête plus simple qui est censée afficher pour chaque individu la date de première observation et la dernière ce qui donne:

SELECT ind.name as "Name"
     , S1.date as "First observation"
     , S2.date as "Last observation"
FROM individuals as ind
inner join sightings as S1
   on S1.individual_ID = ind.individual_ID 
left join sightings as S2
   on S2.individual_ID = ind.individual_ID  
WHERE NOT EXISTS 
(SELECT 1 FROM sightings as S1b WHERE S1.date > S1b.date and S1.individual_ID = S1b.individual_ID )
order by ind.name
       , S1.date
       , S2.date
; 

Mais ça affiche X lignes par individu avec la date de première observation et toutes les autres dates d'observation
Et si je mets S2 à la place de S1b ça ne change rien, en intégrant le WHERE dans le inner join S2 non plus, pareil si je ne fais aucun inner join.
J'ai même essayé de remplacer 1 par S2.date ou s1b.date mais ça ne change rien

Non, il ne faut pas joindre à gauche sur S2.

Tu fais ta jointure simple sur S1 et S2 :


SELECT ind.name as "Name"
     , S1.date as "First observation"
     , S2.date as "Last observation"
FROM individuals as ind, sightings  S1, sightings  S2
WHERE 
(
S1.individual_ID = ind.individual_ID
AND S2.individual_ID = ind.individual_ID
AND S2.individual_ID = S1.individual_ID -- ajout de la transitivité au cas où
)

AND NOT EXISTS 
(SELECT 1 FROM sightings as S1b WHERE S1.date > S1b.date and S1.individual_ID = S1b.individual_ID )
AND NOT EXISTS 
(SELECT 1 FROM sightings as S2b WHERE S2.date < S2b.date and S1.individual_ID = S1b.individual_ID )

order by ind.name
       , S1.date
       , S2.date
; 

Sauf erreur de ma part cela devrait donner ce que tu recherches.

En règle générale, il faut éviter le "WHERE t1.sequence = (SELECT max(t2.squence) FROM t2 WHERE t1.id = t2.id)" parce que le max() est volatile, donc recalculé à chaque fois. Donc si ton ID possède 100 séquences, tu as un produit cartésien 100x100 = 10.000

Avec un "NOT EXISTS (SELECT 1 FROM t2 WHERE t1.sequence > t2.sequence and t1.id = t2.id )" chaque mauvais candidat sera éliminé dès qu'il sera trouvé une ligne avec une séquence supérieure. Donc, si tu as beaucoup de chance tu vas avoir un 100 + 99*1 = 199 ; et si tu es vraiment poissard tu vas avoir un 100x100=10.000.

Donc dans le pire des cas, tu te retrouves dans le cas du max() qui lui est de toute façon le pire des cas de manière constante.

"

Pied de page des forums

Propulsé par FluxBB