web-dev-qa-db-fra.com

L'UUID en tant que clé primaire dans PostgreSQL donnera-t-il de mauvaises performances d'index?

J'ai créé une application dans Rails sur Heroku en utilisant une base de données PostgreSQL.

Il dispose de quelques tableaux conçus pour pouvoir se synchroniser avec des appareils mobiles où les données peuvent être créées à différents endroits. À cet effet, j'ai un champ uuid qui est une chaîne stockant un GUID en plus d'une clé primaire d'incrémentation automatique. L'uuid est celui qui est communiqué entre le serveur et les clients.

J'ai réalisé après avoir implémenté le moteur de synchronisation côté serveur que cela entraînait des problèmes de performances lors de la nécessité de mapper entre uuid <-> id tout le temps (lors de l'écriture d'objets, je dois demander l'uuid pour obtenir l'id avant l'enregistrement et le opposé lors du renvoi des données).

Je pense maintenant à passer à n'utiliser que l'UUID comme clé primaire, ce qui rend l'écriture et la lecture beaucoup plus simples et plus rapides.

J'ai lu que l'UUID en tant que clé primaire peut parfois donner de mauvaises performances d'index (fragmentation d'index) lors de l'utilisation d'un index de clé primaire en cluster. PostgreSQL souffre-t-il de ce problème ou est-il correct d'utiliser UUID comme clé primaire?

J'ai déjà une colonne UUID aujourd'hui, donc en termes de stockage, ce sera mieux parce que je supprime la colonne id régulière.

57
thejaz

(Je travaille sur Heroku Postgres)

Nous utilisons les UUID comme clés primaires sur quelques systèmes et cela fonctionne très bien.

Je vous recommande d'utiliser le uuid-ossp extension, et même que postgres génère des UUID pour vous:

heroku pg:psql
psql (9.1.4, server 9.1.6)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

dcvgo3fvfmbl44=> CREATE EXTENSION "uuid-ossp"; 
CREATE EXTENSION  
dcvgo3fvfmbl44=> CREATE TABLE test (id uuid primary key default uuid_generate_v4(), name text);  
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE  
dcvgo3fvfmbl44=> \d test
                 Table "public.test"  
Column | Type |              Modifiers              
--------+------+-------------------------------------  
id     | uuid | not null default uuid_generate_v4()  name   | text |  
Indexes:
    "test_pkey" PRIMARY KEY, btree (id)

dcvgo3fvfmbl44=> insert into test (name) values ('hgmnz'); 
INSERT 0 1 
dcvgo3fvfmbl44=> select * from test;
                  id                  | name  
--------------------------------------+-------   
 e535d271-91be-4291-832f-f7883a2d374f | hgmnz  
(1 row)

Modifications des performances d'EDIT

Cela dépendra toujours de votre charge de travail.

La clé primaire entière a l'avantage de la localité où les données similaires se rapprochent. Cela peut être utile, par exemple pour les requêtes de type plage telles que WHERE id between 1 and 10000 bien que le conflit de verrouillage soit pire.

Si votre charge de travail de lecture est totalement aléatoire dans la mesure où vous effectuez toujours des recherches de clé primaire, il ne devrait pas y avoir de dégradation des performances mesurable: vous ne payez que pour le type de données plus volumineux.

Écrivez-vous beaucoup à ce tableau et ce tableau est-il très grand? Il est possible, bien que je n'aie pas mesuré cela, qu'il y ait des implications dans le maintien de cet indice. Pour de nombreux ensembles de données, les UUID sont très bien, cependant, et l'utilisation des UUID comme identifiants a quelques belles propriétés.

Enfin, je ne suis peut-être pas la personne la plus qualifiée pour discuter ou donner des conseils à ce sujet, car je n'ai jamais exécuté une table assez grande avec un PK UUID où cela est devenu un problème. YMMV. (Cela dit, j'aimerais entendre parler de personnes qui rencontrent des problèmes avec l'approche!)

58
hgmnz

Comme l'indique la réponse acceptée, les requêtes de plage peuvent être lentes dans ce cas, mais pas seulement sur id.

L'auto-incrémentation est naturellement triée par date, donc lorsque l'auto-incrémentation est utilisée, les données sont stockées chronologiquement sur le disque (voir B-Tree), ce qui accélère les lectures (pas de recherche de disques durs). Par exemple, si l'on répertorie tous les utilisateurs, l'ordre naturel serait par date de création, ce qui est le même que l'auto-incrémentation et que les requêtes de plage s'exécutent plus rapidement sur les disques durs tandis que sur SSD, je suppose que la différence serait inexistante car les SSD sont par conception toujours aléatoires accès (pas de recherche de tête, pas de pièces mécaniques impliquées, juste de l'électricité pure)

1
asdfasdfads