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

Quel est l'ordre des enregistrements dans une table avec une clé primaire composite

Cette question fait l'hypothèse erronée que la clé primaire impose un ordre de table du tout. Ce n'est pas le cas. Les tables PostgreSQL n'ont pas d'ordre défini, avec ou sans clé primaire; il s'agit d'un "tas" de lignes disposées en blocs de pages. L'ordre est imposé à l'aide du ORDER BY clause de requêtes lorsque vous le souhaitez.

Vous pensez peut-être que les tables PostgreSQL sont stockées sous forme de tables orientées index qui sont stockées sur le disque dans l'ordre des clés primaires, mais ce n'est pas ainsi que Pg fonctionne. Je pense qu'InnoDB stocke les tables organisées par la clé primaire (mais n'a pas vérifié), et c'est facultatif dans les bases de données d'autres fournisseurs en utilisant une fonctionnalité souvent appelée "index cluster" ou "tables organisées en index". Cette fonctionnalité n'est actuellement pas prise en charge par PostgreSQL (à partir de la version 9.3 au moins).

Cela dit, la PRIMARY KEY est implémenté en utilisant un UNIQUE index, et il y a un ordre à cet index. Il est trié par ordre croissant à partir de la colonne de gauche de l'index (et donc de la clé primaire), comme s'il s'agissait de ORDER BY col1 ASC, col2 ASC, col3 ASC; . Il en va de même pour tout autre index b-tree (par opposition à GiST ou GIN) dans PostgreSQL, car ils sont implémentés à l'aide de b+trees.

Donc dans le tableau :

CREATE TABLE demo (
   a integer,
   b text, 
   PRIMARY KEY(a,b)
);

le système créera automatiquement l'équivalent de :

CREATE UNIQUE INDEX demo_pkey ON demo(a ASC, b ASC);

Cela vous est signalé lorsque vous créez une table, par exemple :

regress=>     CREATE TABLE demo (
regress(>        a integer,
regress(>        b text, 
regress(>        PRIMARY KEY(a,b)
regress(>     );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "demo_pkey" for table "demo"
CREATE TABLE

Vous pouvez voir cet index lors de l'examen du tableau :

regress=> \d demo
     Table "public.demo"
 Column |  Type   | Modifiers 
--------+---------+-----------
 a      | integer | not null
 b      | text    | not null
Indexes:
    "demo_pkey" PRIMARY KEY, btree (a, b)

Vous pouvez CLUSTER sur cet index pour réorganiser la table en fonction de la clé primaire, mais c'est une opération unique. Le système ne conservera pas cet ordre - bien que s'il y a de l'espace libre dans les pages en raison d'un FILLFACTOR autre que celui par défaut Je pense qu'il va essayer.

Une conséquence de l'ordre inhérent de l'index (mais pas du tas) est qu'il est beaucoup recherche plus rapide :

SELECT * FROM demo ORDER BY a, b;
SELECT * FROM demo ORDER BY a;

que :

SELECT * FROM demo ORDER BY a DESC, b;

et aucun de ceux-ci ne peut utiliser l'index de clé primaire, ils feront un seqscan à moins que vous n'ayez un index sur b :

SELECT * FROM demo ORDER BY b, a;
SELECT * FROM demo ORDER BY b;

C'est parce que PostgreSQL peut utiliser un index sur (a,b) presque aussi rapide qu'un index sur (a) seule. Il ne peut pas utiliser un index sur (a,b) comme s'il s'agissait d'un index sur (b) seul - même pas lentement, ça ne peut tout simplement pas.

Quant au DESC entrée, pour cela, un Pg doit effectuer un balayage d'index inverse, qui est plus lent qu'un balayage d'index avant ordinaire. Si vous voyez beaucoup de balayages d'index inversés dans EXPLAIN ANALYZE et vous pouvez vous permettre le coût de performance de l'index supplémentaire, vous pouvez créer un index sur le champ dans DESC commande.

Ceci est vrai pour WHERE clauses, pas seulement ORDER BY . Vous pouvez utiliser un index sur (a,b) pour rechercher WHERE a = 4 ou WHERE a = 4 AND b = 3 mais pas pour rechercher WHERE b = 3 seule.