Question

J'ai un tableau de 5 651 744 lignes, avec une clé primaire composée de 6 colonnes (int x 3, smallint, varchar (39), varchar (2)). Je cherche à améliorer les performances avec cette table et une autre table qui partage cette clé primaire plus une colonne supplémentaire ajoutée mais comportant 37 millions de lignes.

En prévision de l'ajout d'une colonne pour créer la clé de hachage, j'ai effectué une analyse et répertorié 18 733 collisions.

SELECT  SUM(CT)
FROM    (
         SELECT HASH_KEY
               ,COUNT(*) AS CT
         FROM   (
                 SELECT CHECKSUM(DATA_DT_ID, BANK_NUM, COST_CTR_NUM,
                                 GL_ACCT_NUM, ACCT_NUM, APPN_CD) AS HASH_KEY
                 FROM   CUST_ACCT_PRFTBLT
                ) AS X
         GROUP BY HASH_KEY
         HAVING COUNT(*) > 1
        ) AS Y

SELECT  COUNT(*)
FROM    CUST_ACCT_PRFTBLT

C’est environ deux fois plus mauvais avec BINARY_CHECKSUM ()

Cela vous semble-t-il trop élevé (0,33%) compte tenu de la taille relative plus petite de l'espace de destination que je couvre? Et si les collisions sont aussi élevées, y a-t-il un avantage à associer cette première clé fabriquée en une seule pour le coût des 4 octets supplémentaires par ligne, étant donné que vous devez toujours vous joindre sur les colonnes normales pour gérer les collisions occasionnelles?

Était-ce utile?

La solution

Je ne vois pas en quoi ajouter une somme de contrôle vous rapporterait quelque chose avec ce niveau de collisions. Même une collision est trop, car vous risqueriez de vous associer à de mauvaises données. Si vous ne pouvez pas garantir la connexion au bon enregistrement, il est inutile d'améliorer les performances mais de gâcher l'intégrité des données. Cela semble être des données financières, alors vous feriez mieux de vous assurer que vos requêtes ne donneront pas de mauvais résultats. Vous risqueriez de débiter ou de créditer les mauvais comptes en cas de collision.

Si vous suivez cette voie, Marc a raison de dire que vous devriez si possible pré-calculer (ajouter un calcul qui doit être appliqué à chaque enregistrement de plusieurs millions de tables d’enregistrement ne devrait pas améliorer les performances). Peut-être que si vous pouvez créer la colonne précalculée (et que vous aurez besoin de déclencheurs pour la maintenir à jour), vous n'aurez peut-être pas besoin de rejoindre les six autres colonnes pour éviter les collisions. Ensuite, vous avez peut-être des performances améliorées. Tout ce que vous pouvez faire, c'est tester votre théorie. Mais soyez sûr de ne pas avoir de collision.

Avez-vous envisagé d'utiliser une clé de substitution, puis un index unique sur les six champs de clé naturelle? Ensuite, vous pourriez rejoindre la clé de substitution et cela améliorerait probablement les performances. Il n'est pas efficace de joindre six colonnes (une varchar) à la place d'une clé de substitution. Je me rends compte que, compte tenu de la taille des données, il pourrait être plus difficile de procéder à une refactorisation que dans un système non productif, mais en réalité, il pourrait être utile de prendre du temps pour réparer de façon permanente les problèmes de performances persistants. Vous êtes le seul à pouvoir dire à quel point ce changement serait complexe et à quel point il serait difficile de remplacer tous les sps ou requêtes par une meilleure jointure. Cependant, il pourrait être possible d'essayer.

Autres conseils

Ce que j’ai vu beaucoup de gens s’écrouler jusqu’à présent, c’est que CHECKSUM a une tonne de collisions, par Admission propre de Microsoft . C'est même pire que MD5 , qui a sa part de collisions significatives.

Si vous souhaitez obtenir une colonne de hachage, envisagez d'utiliser HASHBYTES avec SHA1 spécifié.   SHA1 a des collisions beaucoup moins significatives que MD5 ou CHECKSUM . Par conséquent, CHECKSUM ne doit jamais être utilisé pour déterminer si une ligne est unique, mais plutôt comme une vérification rapide de la fidélité de deux valeurs. Par conséquent, votre taux de collision doit être égal à 0% avec HASHBYTES , sauf si vous avez des lignes en double (qui, en tant que PK, ne devrait jamais se produire).

N'oubliez pas que HASHBYTES tronquera tout ce qui est supérieur à 8 000 octets, mais que votre clé PK est beaucoup moins que cela (tous concaténés), vous ne devriez donc pas avoir de problèmes.

Si votre somme de contrôle la réduit à 0,33% des données, alors je dirais que cela fonctionne bien ... surtout si vous utilisez cette colonne en combinaison avec d'autres colonnes (indexées).

Bien sûr, pour être efficace en tant qu'index, vous souhaiterez probablement calculer et stocker cette valeur lors de l'insertion / mise à jour de données, avec un index non clusterisé.

Bien sûr, un index fractionné régulier sur les colonnes en question peut tout aussi bien ou mieux…

Si vos requêtes sont sélectives et que l'index en cluster de la table de lignes est étroit ou inexistant, un index non groupé sur la somme de contrôle de la table de lignes devrait offrir de bonnes performances.

Après avoir appliqué le critère, quel qu’il soit, à la table d’en-tête, il utilisera la somme de contrôle pour effectuer une recherche d’index sur l’index non mis en cluster. Vous devez toujours inclure les FK dans la jointure, mais les critères de jointure sans somme de contrôle seront appliqués après la recherche dans l'index, après la recherche dans le signet. Très efficace.

Vous souhaitez optimiser la recherche dans l'index. La somme de contrôle est déjà très sélective. L'ajout de FK augmenterait la taille de l'index et les E / S correspondantes et ne serait d'aucune aide s'il n'incluait pas suffisamment de champs pour éviter complètement la recherche de signet.

Etant donné que l'index non clusterisé contient les clés de clustering ou le pointeur de tas, vous souhaitez soit a) une petite clé de clustering (par exemple, une colonne d'identité int - pointeur à 4 octets), soit b) aucun index clusterisé (8). point d’octet).

Si vos requêtes ne sont pas sélectives ou si l'index clusterisé de la table de lignes est énorme (la table entière moins quelques colonnes), je ne sais pas si la somme de contrôle vous aiderait (navigation plus rapide dans l'index, peut-être?). Dans tous les cas, vous voudriez en faire un index clusterisé ou couvrant, et si la table d'en-tête n'est pas clusterisée en premier sur la somme de contrôle, le tri sera important.

Si vous pouvez vous permettre les coûts de stockage et d’indexation, quelques index couvrants - en-tête et détails - peuvent être la solution.

SI votre PRIMARY KEY est groupé, chaque index que vous créez contiendra ce PRIMARY KEY .

La jonction sur une valeur hachée utilisera les étapes suivantes:

  1. Localisez la valeur hachée dans la clé d'index
    • Localisez la valeur PRIMARY KEY dans les données d'index
    • Utilisez la recherche d'index en cluster pour localiser la ligne PRIMARY KEY dans la table

La jointure sur une PRIMARY KEY utilise uniquement l'étape 3 .

SQL Server , cependant, est assez intelligent pour en tenir compte, et si vous vous y joignez comme ceci:

SELECT  *
FROM    main_table mt
JOIN    CUST_ACCT_PRFTBLT cap
ON      cap.HASH_KEY = mt.HASH_KEY
        AND cap.DATA_DT_ID = mt.DATA_DT_ID
        AND …
WHERE   mt.some_col = @filter_value

, il n'utilisera pas l'index sur HASH_KEY , mais utilisera un seul index clusterisé et un filtre pour créer assurez-vous que les valeurs de hachage correspondent (et elles le feront toujours).

Résumé : rejoignez simplement la PRIMARY KEY .

À l'aide d'un index secondaire, vous devez d'abord effectuer une recherche inutile HASH_KEY , puis continuer à vous joindre à la PRIMARY KEY .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top