Envoyé par
Donpi
Bonjour,
Alors voilà j'ai besoin de calculé un Hash SHA1 pour chaque record de chaque table qui va servir d'identifiant.
Ce hash est calculé sur certaines colonnes des tables pas toujours les mêmes d'une table à l'autre.
En revanche la chaine hashée doit avoir un format très précis pour évité les duplicats.
Du coup il est important que son calcul ne soit qu'a un seul endroit pour être certain qu'il est le même d'un dev à l'autre, régénérable, maintenable, etc...
Donc vous aller créer un hotspot qui induira des problèmes de performance...
Bref, quels seraient vos idées / propositions pour ce problème ?
A suivre quelques précisions
- Oui je sais que les hash ont un risque de créer des doublons. Mais tellement infime que ce risque est ignoré.
- J'utilise un Hash plutôt qu'un GUID pour qu'il puisse être connu a l'avance et régénérable.
Un GUID peut lui aussi être généré à l'avance. Dans tous les langage de programmation vous avez une fonction de génération des GUID. Exemple en C# NewGuid(). Vous pouvez aussi appeler la fonction NEWID() de SQL Server dans une requête préalable. Exemple ;
- J'ai essayer d'utiliser les fonction de Hash de sql serveur, mais comme les paramètres doivent être fixe, c'est compliqué.
Enfin la solution actuellement implémentée qui ne satisfait pas complétement
Nous avons créé une CLR qui prendre un nombre variable de SQLVariant en paramètres.
La CLR fait parfaitement le travail mais pose les problèmes suivants :
- Les [n]Varchar(MAX) ne fonctionnent pas car ne peuvent pas être converti en SQL variant.
C'est totalement faux, il suffit d'utiliser la fonction CAST... qui est faite pour cela !
Mais stocker une valeur binaire dans du texte est une idiotie. Utilisez du binaire. Par exemple BINARY(20)...
- Les CLR ont un nombre de paramètres défini, j'ai du donc créé une SP pour chaque nombre de paramètres.
ça n'a aucun sens de créer une procédure pour cela. Un simple fonction suffit !
- Dans les requêtes simples ça va très vite mais dés que c'est un peu compliqué l'Optimiseur pète un câble et une requête de 20 secondes passe à 1h. Un work around à ce dernier point est de stocker les hashs calculés dans une table temporaire puis d'utiliser cette dernière dans la requête complexe.
Dans tous les cas vous aurez des problèmes de performance. En effet une clé pour être efficace doit être la plus petite possible. Un GUID c'est 16 octets ce qui impose une double lecture dans le processeur 64 bits (=8 octets) donc coute deux fois plus cher qu'un BIGINT... comme clé. De plus, comme les valeurs sont aléatoires, il y aura fragmentation des index. Tout ceci pèsera fortement sur les performances...
Quand au hash c'est pire encore... 20 octets pour le SHA1 ! Donc 3 passe dans le processeur, 6 pour faire une jointure.... Et fragmentation.
Sans parler de la lourdeur de la clé dont le nombre d'octets pèsera sur les sauvegardes, la maintenance...
C'est donc une très mauvaise idée, que l'on rencontre fréquemment chez les développeurs qui ne maîtrisent pas le fonctionnement des SGBDR !
Pourquoi ne pas utiliser un autoincrément à partir d'une séquence ? Il suffit de demander la nouvelle valeur avec :
SELECT NEXT VALUE FOR MaSequence AS NOUVEL_ID;
Puis de l'utiliser dans la requête...
A +
Partager