web-dev-qa-db-fra.com

CURRENT_TIMESTAMP peut-il être utilisé en tant que CLÉ PRIMAIRE?

Pouvez CURRENT_TIMESTAMP être utilisé comme PRIMARY KEY?

Y a-t-il une possibilité que deux ou plusieurs INSERTs différents obtiennent le même CURRENT_TIMESTAMP?

10
John Puskin

Selon le documentation , la précision du CURRENT_TIMESTAMP est en microsecondes. Ainsi, la probabilité d'une collision est faible, mais possible.

Imaginez maintenant un bogue qui se produit très rarement et provoque des erreurs de base de données. Est-il difficile de le déboguer? C'est un bug bien pire que celui qui est au moins déterministe.

Le contexte plus large: vous voulez probablement éviter ces petites nuances avec les séquences, ce qui est particulièrement gênant si vous êtes habitué à MySQL.

De plus, si vous utilisez des transactions (la plupart des frameworks web, en particulier les Java ceux, faites-le!), Les horodatages seront les mêmes à l'intérieur d'une transaction! Une démonstration:

postgres=# begin;
BEGIN
postgres=# select current_timestamp;
       current_timestamp       
-------------------------------
 2018-08-06 02:41:42.472163+02
(1 Zeile)

postgres=# select current_timestamp;
       current_timestamp       
-------------------------------
 2018-08-06 02:41:42.472163+02
(1 Zeile)

À plus? Deux sélections, exactement le même résultat. Je ne tape pas si vite. ;-)

-

Si vous voulez facilement des identifiants, en évitant l'utilisation des séquences, générez une valeur de hachage à partir des vrais identifiants des enregistrements. Par exemple, si votre base de données contient des humains et que vous savez que leur date de naissance, le nom de jeune fille de leur mère et leur vrai nom les identifient de manière unique, utilisez un

md5(mother_name || '-' || given_name || '-' birthday);

comme id. À côté de cela, vous pouvez utiliser une colonne CreationDate, après ce que vous indexez la table, mais ce n'est pas une clé (qui est l'id).

P.s. En général, c'est une très bonne pratique de rendre votre base de données aussi déterministe que possible. C'est à dire. la même opération devrait créer exactement le même changement dans la base de données . Tout ID basé sur l'horodatage ne parvient pas à cette fonctionnalité importante. Et si vous voulez déboguer ou simuler quelque chose? Vous rejouez une opération et le même objet sera créé avec un identifiant différent ... ce n'est vraiment pas difficile à suivre, et cela épargne beaucoup de Heures de travail.

P.s.2 Quiconque vérifiera votre code à l'avenir n'aura pas la meilleure opinion des identifiants générés par l'horodatage, pour les raisons ci-dessus.

Pas vraiment, car il est possible pour CURRENT_TIMESTAMP de fournir deux valeurs identiques pour deux INSERT suivants (ou un INSERT unique avec plusieurs lignes).

Utilisez plutôt un UUID basé sur le temps: id_generate_v1mc () .

10
Linas

À proprement parler: Non. Parce que CURRENT_TIMESTAMP est une fonction et une ou plusieurs colonnes de table peuvent former un PRIMARY KEY contrainte.

Si vous souhaitez créer un PRIMARY KEY contrainte sur une colonne avec la valeur par défaut CURRENT_TIMESTAMP, alors la réponse est: Oui, vous pouvez . Rien ne vous empêche de le faire, comme rien ne vous empêche de tirer des pommes de la tête de votre fils. La question n'aurait toujours pas de sens tant que vous n'en définiriez pas le but. Quels types de données les colonnes et les tables sont-elles censées contenir? Quelles règles essayez-vous de mettre en œuvre?

En règle générale, l'idée est liée à des erreurs de clé en double depuis CURRENT_TIMESTAMP est une fonction STABLE renvoyant la même valeur pour la même transaction (l'heure de début de la transaction). Plusieurs INSERT dans la même transaction sont susceptibles de se heurter - comme d'autres réponses déjà illustrées. Le manuel:

Étant donné que ces fonctions renvoient l'heure de début de la transaction en cours, leurs valeurs ne changent pas pendant la transaction. Ceci est considéré comme une caractéristique: l'intention est de permettre à une seule transaction d'avoir une notion cohérente de l'heure "actuelle", de sorte que plusieurs modifications au sein d'une même transaction portent le même horodatage.

Les horodatages PostgreSQL sont implémentés sous forme d'entiers de 8 octets représentant jusqu'à 6 chiffres fractionnaires (résolution en microsecondes).

Si vous construisez une table qui ne doit pas contenir plus d'une ligne par microseconde et que cette condition ne changera pas (quelque chose nommé sensor_reading_per_microsecond), puis cela pourrait avoir un sens. Les lignes en double sont supposées pour déclencher une erreur de violation de clé en double. C'est une exception exotique, cependant. Et le type de données timestamptz (pas timestamp) serait probablement préférable. Voir:

Je préfère toujours utiliser une clé primaire série de substitution à la place. Et ajoutez une contrainte UNIQUE sur la colonne d'horodatage. Moins de complications possibles, sans compter sur les détails de mise en œuvre du SGBDR.

7
Erwin Brandstetter