Vous n'êtes pas identifié(e).
Il y a apparemment deux problèmes liés à GROUP BY dans cette requête.
1) Il faut utiliser WHERE et non pas HAVING pour filtrer les lignes de la table missions. L'utilisation de HAVING est réservée aux conditions qui s'appliquent aux résultats aggrégés avec GROUP BY.
2) le GROUP BY tranche semble ne pas avoir de sens puisque la tranche est elle même le résultat d'une aggrégation par semaine.
Si la requête est trop complexe il faut il y aller progressivement et la construire étage par étage en validant les étapes intermédiaires.
J'imagine que PostgreSQL est installé sur un poste Windows et que pgAdmin est lancé sur le même PC (pgAdmin et PostgreSQL sont deux logiciels distincts: pgAdmin est un client et PostgreSQL un serveur).
Par rapport à la copie d'écran dans le champ en haut Hostname/address if faut mettre localhost comme valeur.
Problème, des vues (au moins 1) m'a retourné une erreur :
elle utilise l'attribut consrc de pg_constraint de la 9.6 qui n'existe plus à partir de pg12.Est-ce que pg_upgrade de pg11 prend ce changement en considération et effectuera les changements ? Cela signifierait migrer de 9.6 vers 11, puis 11 vers 12 et enfin 12 vers 13 ?
Sinon, dois-je supprimer les vues en question avant et les recréer ensuite (post migration) ?
Non pg_upgrade ne peut pas gérer ça. La doc recommande d'utiliser la fonction pg_get_constraintdef() pour retrouver la définition d'une contrainte au lieu de la colonne consrc qui n'existe plus à partir de la version 12.
Le faire avant ou après la migration, c'est à vous de voir ce qui est le plus pratique pour vous.
Il y a des services web ouverts au public qui permettent de saisir du SQL dans une page web pour s'entraîner à faire des requêtes, mais généralement pas de s'authentifier via un client SQL. Par exemple sqlfiddle.com est assez connu mais il y en a d'autres.
Concernant les bases opendata, il y en a plein mais sous forme téléchargeable de fichiers SQL ou de fichiers CSV ou JSON, il faut les
charger dans son propre serveur.
Si vous avez installé PostgreSQL sur votre PC vous pouvez vous authentifier sur votre propre serveur et faire ce que vous voulez dessus.
La première requête n'est pas correcte car elle joint avec la seule condition pc.relname=pt.tablename, en ignorant le schéma.
Plutôt utiliser cette version:
select n.nspname, c.relname from
pg_class c join pg_namespace n on c.relnamespace=n.oid
and nspname!='pg_catalog'
and relhasoids;
Dans la requête du message #1 il y a un S1.troop_id impliqué dans le GROUP BY qui potentiellement change le nombre de lignes du résultat. Et autant pour les autres colonnes on comprend intuitivement à quoi elles correspondent, autant pour celle-là il faudrait des explications pour savoir quoi faire avec et comprendre en quoi elle influe sur le résultat.
Pour l'absence possible de 2eme date d'observation, en effet c'est un LEFT JOIN entre S1 et S2 donc S2 va avoir des colonnes correspondantes à NULL dans ces cas. C'est gérable avec le fenêtrage, pour ces cas la colonne first_date va être égale à last_date pour le même individu. Les colonnes de la 2nde observation inexistante pourraient être mises à NULL dans un étage supérieur de la requête avec des expressions du style CASE WHEN date2=date1 THEN null else date2 END.
Peut-être qu'un fenêtrage serait une bonne solution ici. A ce que je comprends on cherche la 1ere et dernière date d'observation par individu, et en même temps certaines autres colonnes liées à ces observations (c'est là que mysql simplifie les choses alors que le standard non)
L'idée serait de déclarer une fenêtre de ce genre là:
WINDOW w AS (PARTITION BY individual_ID ORDER BY date ROWS between unbounded preceding and unbounded following)
Ensuite on va parcourir un seule fois la table sightings (pas d'auto-jointure) et demander la 1ere et dernière ligne de chaque partition, avec ce genre d'expression
SELECT
first_value(date) OVER w as "first date",
last_value(date) OVER w as "last_date",
first_value(autre_colonne) OVER w As "valeur d'une autre colonne correspondant à first date",
last_value(autre_colonne) OVER w As "valeur d'une autre colonne correspondant à last date",
etc...
FROM sigthings
WINDOW w AS (PARTITION BY individual_ID ORDER BY date ROWS between unbounded preceding and unbounded following)
Ensuite pour aggréger ce résultat et ne garder qu'une ligne par partition on peut ajouter un étage supérieur DISTINCT ON (voir https://www.postgresql.org/docs/current … -DISTINCT). Généralement on ordonne les lignes présentées à DISTINCT ON par l'expression de déduplication mais dans ce cas particulier il n'est même pas nécessaire de faire un ORDER BY parce que toutes les lignes relatives à un même individual_ID (même partition) vont être égales.
A l'étage encore au-dessus il y aurait une jointure avec la table individuals via individual_ID pour retrouver les colonnes de cette table du style "Name", "Sex".
Avec Debian chaque instance postgres a son répertoire de config , par exemple /etc/postgresql/14/main si c'est Postgres version 14 et que le nom du cluster est "main" (le nom par défaut).
Dans le doute, utiliser la commande pg_lsclusters pour avoir la liste des instances.
Dans ce répertoire il y a un fichier start.conf avec ce contenu:
# Automatic startup configuration
# auto: automatically start the cluster
# manual: manual startup with pg_ctlcluster/postgresql@.service only
# disabled: refuse to start cluster
# See pg_createcluster(1) for details. When running from systemd,
# invoke 'systemctl daemon-reload' after editing this file.
auto
Remplacer auto par manual pour ne pas démarrer automatiquement.
Source: https://manpages.debian.org/buster/post … .1.en.html
Dans le trigger:
RETURN NEW;
-- mettre à jour la vue matérialisée
REFRESH MATERIALIZED VIEW schema_1.v_mat_1_utilisateur1;
Le RETURN NEW fait sortir du trigger donc le REFRESH n'est pas exécuté. Le RETURN NEW doit se faire en dernier.
Sinon d'un point de vue conception, ça paraît extrêmement lourd de rafraîchir une vue matérialisée à chaque mise à jour de ligne.
Peut-être qu'il serait intéressant de creuser les raisons pour lesquelles les vues non matérialisées limitant les données exposées à QGIS ne donnent pas satisfaction. Est-ce que c'est les requêtes qui sont lentes ou c'est QGIS?
Si c'est les requêtes, il faudrait faire des EXPLAIN ANALYZE pour voir où le temps est consommé et pourquoi. Il y a des conseils à ce sujet dans https://wiki.postgresql.org/wiki/Slow_Query_Questions
Pour avoir la liste des colonnes changées quelque soit la structure de la table, on peut utiliser une requête de ce style, qui fait l'intersection de OLD et NEW pour ne garder que ce qui change:
select array_agg(k2)
from (select * from jsonb_each_text(row_to_json(OLD)::jsonb)) as r1(k1,v1)
join (select * from jsonb_each_text(row_to_json(NEW)::jsonb)) as r2(k2,v2)
on k1=k2
where v1 is distinct from v2;
Il y a une version avec hstore aussi, où on peut faire encore plus simplement
hstore(NEW.*) - hstore(OLD.*)
Mais hstore étant rendu obsolète par jsonb, ce n'est pas forcément une bonne idée de partir là dessus aujourd'hui.
La version "toutes options" du trigger d'audit avec hstore est maintenue ici:
https://github.com/2ndQuadrant/audit-tr … /audit.sql
Il faudrait regarder dans les logs du serveur s'il y a un autre message. C'est peut-être ce message là qui a un problème d'encodage.
La redistribution de la clef primaire échoue via l'UPDATE du fait que Postgres ne teste pas l'unicité à la fin de l'instruction, comme indiqué ici dans la doc:
https://doc.postgresql.fr/14/sql-set-constraints.html
De plus, PostgreSQL vérifie les contraintes uniques non déferrables immédiatement, pas à la fin de l'instruction comme le standard le suggère.
Pour que l'UPDATE passe, il faudrait que la contrainte soit DEFERRABLE INITIALLY DEFERRED ou DEFERRABLE tout court et que la transaction la passe en DEFERRED.
L'autre solution est de ne pas faire un UPDATE mais de réinsérer les lignes avec DELETE+INSERT:
with d as (delete from table returning *)
insert into table select row_number() over (order by Nom), Nom from d;
Je suggère row_number() au lieu de rank() parce que rank() créé des doublons en cas d'égalité
timestamptz est l'abbréviation de timestamp with time zone
C'est précisé dans la doc via cette note:
Le standard SQL impose que timestamp soit un équivalent de timestamp without time zone. timestamptz est accepté comme abréviation pour timestamp with time zone ; c'est une extension PostgreSQL.
En vrac, il y a plusieurs soucis visibles dans le code montré
- BEGIN MAJ
Pourquoi MAJ? La syntaxe valide c'est BEGIN tout seul.
- FETCH ALL FROM cLecture;
La syntaxe est FETCH [ direction { FROM | IN } ] curseur INTO cible;
ALL n'est pas possible. La cible devrait probablement être rt la variable déclarée mais pas utilisée. S'il n'y a aucune cible à avoir, un MOVE cLecture ferait mieux l'affaire.
Attention au fait que la syntaxe du FETCH en plpgsql diffère du FETCH du SQL. C'est piégeux mais c'est une règle générale. Le plpgsql a sa propre syntaxe qui ressemble superficiellement au SQL mais qui diffère à cause des variables et du côté procédural.
- COMMIT à supprimer
- la requête du curseur n'a pas d'ORDER BY donc il faut voir que les valeurs successives de NB vont arriver dans les lignes dans un ordre indéterminé.
Est-ce un exercice? Parce qu'en dehors d'un exercice, ça n'a aucun intérêt de faire une boucle au lieu d'un seul UPDATE qui met à jour toutes les lignes.
A part ça, il faut regarder la doc des curseurs en plpgsql pour les questions de syntaxe et d'usage: https://docs.postgresql.fr/14/plpgsql-cursors.html
Sinon le COMMIT en milieu de boucle pose problème: un COMMIT ferme la transaction en cours et par extension les curseurs qui sont ouverts dedans, sauf s'il sont marqués WITH HOLD. Mais pourquoi faire un COMMIT ici? Quel intérêt?
Bonjour @ tous,
Je rencontre quelques problèmes de timeout sur Postgres lors d'insertion et de mises à jour via APIs.
La volumétrie est importante (33 174 requêtes en 15 minutes avec un pic de 4718 requêtes en 1 minute).
Est-il possible de jouer sur quelques paramètres de Postgres pour accepter ces nombreux flux entrants.
En principe on ne change pas des paramètres sans avoir au moins des hypothèses sur la cause des lenteurs, sauf si les paramètres basiques de tuning comme shared_buffers ou work_mem ne sont cohérents avec les capacités du serveur.
Très souvent on installe l'extension pg_stat_statements pour collecter les requêtes normalisées avec leurs temps d'exécution mix/max/moyen, qui donnent des éléments concrets d'analyse.
Une autre méthode très utilisée est de mettre log_min_duration_statement au seuil de durée d'exécution que vous souhaiteriez que vos requêtes ne dépassent pas. Toutes les requêtes plus longues sortiront dans le log. Ensuite on peut analyser le log avec pgBadger.
Il est aussi recommandé d'activer log_lock_waits, qui permettra de savoir si des requêtes sont lentes parce qu'elles attendent des verrous. Les logs produits sont aussi visibles de manière assez claire dans les rapports pgBadger. Pendant qu'on y est on ajoute souvent log_checkpoints et les logs d'autovacuum, ainsi qu'éventuellement log_temp_files.
Il y a aussi des outils de monitoring qui capturent à fréquence régulière la vue pg_stat_activity (entre autres) pour voir combien de connexions sont occupées à faire quoi. Généralement on regarde ces résultats en même temps que les métriques système d'activité CPU et disque.
Le fait de créer des variables avec DECLARE est une fonctionnalité du langage plpgsql, mais cette fonction est déclarée avec language 'sql', donc DECLARE n'est pas possible. C'est la raison de l'erreur.
Le fait que French_France.28605 ne soit pas proposé dans les listes préremplies de l'installeur ou de pgadmin est une limitation de ces programmes. Idéalement on devrait pouvoir ajouter une valeur non préremplie. Si on ne peut pas le faire, après que Postgres soit installé il faut contourner ça en créant la base avec CREATE DATABASE en SQL.
Dans psql ou dans l'outil de requête de pgadmin, on peut toujours exécuter un ordre SQL de ce style:
CREATE DATABASE nomdelabase
ENCODING = 'LATIN9'
TEMPLATE template0
LC_COLLATE = 'French_France.28605'
LC_CTYPE = 'French_France.28605';
Le nom fr_FR.Iso8855915@euro n'étant pas acceptable par Windows, il faut utiliser un nom de locale acceptable par Windows avec les mêmes fonctionnalités que fr_FR.Iso8855915@euro sous Linux.
Le nom de locale correspondant pour Windows est French_France.28605
Effectivement, il semble qu'on ne puisse pas dire à pg_dump de ne pas lire les séquences liées quand on extrait le contenu d'une table, mais on peut utiliser plus simplement COPY pour exporter le contenu de la table (ce que fait d'ailleurs pg_dump, avec plein d'autres choses qui ne vous intéressent pas dans le cas présent), sans avoir aucun droit sur les séquences liées.
psql [options] -c 'COPY nomtable TO STDOUT' > export-table.sql
Si la table est déjà créée dans la base cible, le contenu peut se recharger dans cette base avec la commande en sens inverse:
psql [options] -c '\copy nomtable FROM export-table.sql'
Si la structure de la table n'existe pas déjà dans la base cible et qui faut l'extraire au préalable de la base source, c'est faisable avec
pg_dump [options] -s -t nomtable > structure-table.sql
qui est utilisable avec un compte en lecture seule sans droit d'accès aux séquences liées à la table.
Il faut regarder dans la définition de la table cible quels sont les triggers et les contraintes d'intégrité différées.
Les contraintes d'intégrité peuvent être supprimées et remises après import.
Pour les triggers ça dépend de ce qu'ils font. Généralement on n'a pas trop envie d'exécuter des millions de triggers sur des imports en masse.
Au passage, ajouter les index après l'import en masse pluôt qu'avant est aussi conseillé pour la durée globale d'import.
UPDATE n'admet pas de clause LIMIT en Postgres, donc la requête telle que proposée n'est pas possible.
Il faudrait plutôt poser la question avec une vraie requête, car la revérification que mentionne Julien en #2 ne suffit pas forcément quand il y a des sous-requêtes.
Vous pouvez tester les UPDATE concurrents à la main avec deux sessions psql en parallèle et des BEGIN COMMIT explicites.
Dans le 3eme champ de .pgpass, il faut mettre replication au lieu d'un nom de base de données.
Si ça échoue toujours après ça, consulter le fichier de log du serveur pour avoir des détails sur l'erreur.
Le fait de mettre password_encryption scram-sha-256 signifie que les mots de passe saisis à compter du changement seront encodés en scram-sha-256. Ca n'a pas d'effet sur l'acceptation ou pas des connexions de comptes avec des mots de passe déjà existants en md5, et donc il n'y pas d'intérêt particulier à rétrograder password_encryption sur postgresql 14.
Sauf si vous avez des vieux clients SQL qui ne savent pas faire du SCRAM (par exemple driver JDBC avant la version 42.2) et que vous ne pouvez pas les mettre à jour. Dans ce cas il faut que tous les comptes anciens comme nouveaux soient en md5, donc password_encryption=md5 obligatoire.
En revanche dans pg_hba.conf si on met scram-sha-256 comme méthode, on exprime que c'est le minimum acceptable. Les comptes qui ont des mots de passe en md5 ne passeront plus. Mais si on met md5, ça veut dire md5 "ou mieux", c'est-à-dire md5 ou scram-sha-256.
Donc en gros, il y a 3 options
1) si on veut se débarasser de md5 maintenant, pour augmenter la sécurité des connexions
- mettre password_encryption=scram-sha-256 et scram-sha-256 à la place de md5 dans pg_hba.conf
- recréer les mots de passe de tous les comptes (et il faut obligatoirement les connaître en clair pour faire ça)
2) si on veut une transition douce, avec un mix scram pour les nouveaux mots de passe, md5 pour les anciens
- mettre password_encryption=scram-sha-256 et laisser md5 dans pg_hba.conf
- ne pas recréer les mots de passe existants
3) si on ne veut pas de scram pour le moment
- mettre password_encryption=md5 et laisser md5 dans pg_hba.conf