PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment garder les données ne trient pas?

La chose cruciale à comprendre est que les tables SQL n'ont pas d'ordre . L'ordre des lignes que vous voyez lorsque vous SELECT sans ORDER BY ne reste le même que parce qu'il est plus rapide pour la base de données de les obtenir dans cet ordre que dans un autre ordre. PostgreSQL ne renverra les lignes que dans cet ordre lorsque vous effectuez un parcours séquentiel sur la table ; s'il peut utiliser un index pour la requête, vous obtiendrez généralement les lignes dans un autre ordre.

Vous pourriez trouver cette réponse que j'ai écrite plus tôt informative.

Dans PostgreSQL, UPDATE s aux lignes peuvent les déplacer vers un emplacement différent dans la table, en modifiant l'ordre dans lequel ils sont renvoyés. Il en va de même pour le processus de vide automatique en arrière-plan et diverses autres opérations telles que VACUUM et CLUSTER .

Vous ne devez donc jamais comptez sur la commande "par défaut" pour quoi que ce soit. Si vous voulez donner une sorte d'ordre aux lignes, elles doivent avoir une clé sur laquelle vous pouvez les trier.

Si vous avez créé une table sans clé et réalisez maintenant qu'elle devrait en avoir une, vous pourrez peut-être vous remettre de la situation en utilisant le ctid colonne système. Ne pas comptez-y pour une utilisation en production, il s'agit d'une colonne interne au système visible par les utilisateurs uniquement à des fins de récupération d'urgence et de diagnostic. Tout d'abord, vérifiez si l'ordre physique sur disque correspond réellement à l'ordre souhaité :

SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;

Si c'est le cas, vous pouvez ajouter une nouvelle colonne de clé prédéfinie à une clé auto-incrémentée appliquée dans l'ordre des lignes sur le disque. Il y a deux façons de faire ça. Le plus sûr est :

BEGIN;
LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE;
ALTER TABLE mytable RENAME TO mytable_old;

CREATE TABLE mytable (id SERIAL PRIMARY KEY, LIKE mytable_old INCLUDING ALL);

INSERT INTO mytable
SELECT row_number() OVER () AS id, *
FROM mytable_old
ORDER BY ctid;

SELECT setval('mytable_id_seq', (SELECT max(id)+1 FROM mytable));

COMMIT;

puis une fois que vous êtes sûr d'être satisfait des résultats, DROP TABLE mytable_old; . Voir cette démo :http://sqlfiddle.com/#!12/2cb99/2

Un moyen simple et rapide, mais moins sûr, consiste simplement à créer la colonne et à compter sur PostgreSQL pour réécrire la table du début à la fin :

ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;

Il n'y a absolument aucune garantie que PostgreSQL attribuera les identifiants dans l'ordre, bien qu'en pratique il le fasse. Voir cette démo SQLFiddle.

Sachez que lorsque vous utilisez une SEQUENCE (qui est ce qu'est un SERIAL colonne crée) il y a quelques comportements auxquels vous ne vous attendez peut-être pas. Lorsque vous insérez plusieurs lignes à la fois, les lignes peuvent ne pas nécessairement recevoir des ID attribués dans l'ordre exact auquel vous vous attendez, et elles peuvent "apparaître" (devenir visibles) dans un ordre différent de l'ordre dans lequel elles ont été attribuées et insérées. En outre, si les transactions sont annulées, l'ID généré est définitivement supprimé, ce qui entraîne des lacunes dans la numérotation. C'est très bien si vous voulez que votre base de données soit rapide, mais ce n'est pas idéal si vous voulez une numérotation sans espace. Si c'est ce dont vous avez besoin, recherchez "postgresql gapless sequence".