web-dev-qa-db-fra.com

SQL Server Colonne d'identité automatique Re-Sheed

Je travaille avec d'énormes jeux de données. Beaucoup de transactions qui se déroulent dans ma base de données sont énormes - trillions de lignes, etc.

Certaines des tables utilisent des colonnes IDENTITY, pas pour les identifiants uniques, simplement parce que c'est simple et rapide, et à fournir une solution simultanée pour fournir un nombre incrémental. Cependant, lorsque la colonne IDENTITY atteint sa limite, je souhaite que cela réside immédiatement dans la déclaration lorsqu'il atteigne sa limite.

J'apprécie que ce soit un comportement étrange pour la plupart, mais cela aurait un sens à au moins avoir cette fonctionnalité comme une option, sûrement? Vous ne pouvez même pas faire une resever dans une transaction, et je ne peux pas utiliser tronquée (ne veut pas supprimer).

Pourquoi n'est-ce pas possible? Quelqu'un d'autre a-t-il déjà rencontré cela comme un problème?

Voici la fonctionnalité: dans SQL Server, j'ai une table qui agit comme générateur de numéros séquentiels, comme une séquence dans Oracle. Le maximum que nous voulons que le nombre soit 999999, après cela, réinitialiser à 0. Ce numéro est ajouté à certains autres champs (l'un d'entre eux un DTESTAMP) pour générer des numéros de référence.

Le système est très concurisé et j'en ai besoin pour être assez évident lorsque le numéro de référence a été généré. Comme il se trouve, il y a une tâche qui fonctionne chaque jour pour réexécuter la colonne IDENTITY, mais en raison du grand nombre d'enregistrements quotidiennement, s'il y a> 999999 enregistrements traités, je reçois une erreur.

5
tuseau

Vous pouvez utiliser le type de données bigint afin d'éviter d'atteindre la valeur maximale trop souvent.

La gamme de Bigint est -2 ^ 63 (-9 223 372 036 854 775 808) à 2 ^ 63-1 (9,223,372,036 854 775 807), stockage = 8 octets. Êtes-vous souvent hors de cette limite?

Au cas où vous voudriez rééorcer, vous devriez être capable de courir le dbcc checkident Déclaration dans une transaction, mais vous devrez faire plus de manutention d'erreur dans votre code.

Je ne connais pas d'une propriété IDENTITY à automatiquement Reaction de sa valeur, seule manuellement, en tronquant la table ou en utilisant dbcc checkident. Vous pouvez créer une gâchette sur votre table et une fois que la dernière valeur insérée se rapproche du maximum, vous pourrez réaliser. Mais cela ajoutera probablement des coûts à vos transactions.

3
Marian

Je suppose que vous avez une nécessité basée sur les entreprises de le faire car ce n'est pas une chose optimale à faire.

Pour faire ce que vous demandez, utilisez une boucle avec TOP 999999 pour le INSERT. Par exemple,

SET ISOLATION_LEVEL SERIALIZABLE;

CREATE TABLE #AlreadyAdded (MyPK int);

--"Prime" the loop
SELECT 0;

WHILE @@rowcount > 0
BEGIN;
    BEGIN TRANSACTION;

    <get the current gap (@GapValue) between 999999 and TargetTable.IdentCol>

    INSERT INTO TargetTable (PKColumn, col1, col2, ...)
        OUTPUT inserted.PKColumn INTO #AlreadyAdded (MyPK)
        SELECT TOP (@GapValue) PKColumn, col1, col2, ...
        FROM   SourceTable AS st
        WHERE  NOT EXISTS (
                       SELECT  0 
                       FROM    #AlreadyAdded AS aa 
                       WHERE   st.PKColumn = aa.MyPK
               )
    ;


    --Reset the identity column to 0 or 1
    DBCC CHECKIDENT ...


    COMMIT TRANSACTION;
END;

Je ne sais pas combien de concurrence dont vous avez besoin pendant que cette transaction est en cours d'exécution. Si vous avez besoin que vos insertions se produisent de manière contiguë, déplacez la transaction commencée/commettre une paire à l'extérieur de la boucle.

En ce qui concerne les autorisations pour DBCC CHECKIDENT: selon Bol, l'appelant doit posséder la table, être dans le rôle de db_owner dB, être dans le rôle de db_ddladmin DB ou être dans le rôle de serveur sysadmin. Donc, si aucun de ceux qui ne s'appliquent, vous pouvez également regarder en utilisant EXECUTE AS <table owner>.

Il existe également une autre option: vous pouvez renoncer à la propriété de colonne IDENTITY et à rouler votre propre générateur de séquence. Vous pouvez également créer des méthodes de transaction-sécurité pour travailler avec elle. Tout comme l'identité, vous pourriez toujours vous retrouver avec des lacunes, de sorte que l'aspect n'est pas mieux ni pire. Je pense que les considérations de test/de maintenance décideraient de le faire.

Tout ce qui a dit, si vous pouvez attendre Denali (SQL Server 2012), la fonction de nouvelles séquences (Nouveau sur SQL Server, c'est-à-dire) est exactement ce que vous recherchez. Il peut avoir une limite supérieure artificielle et un cycle automatiquement.

3
Phil Helmer

Au lieu de retirer l'identité, définissez la colonne d'identité en tant que Bigint, puis utilisez une colonne calculée pour obtenir les 6 derniers chiffres que le nombre compris entre 0 et 999 999:

CREATE TABLE dbo.SomeData
(
    ID bigint IDENTITY(1,1)
    , Digits AS CAST(RIGHT('000000'+CAST(ID AS VARCHAR(20)), 6) AS int)
);

Vous devez vous rendre compte que les 6 derniers chiffres sont une répétition entre 0 et 999999. Voici comment fonctionne les mathématiques.

00000999999
00001000000
00001999999
00002000000
1
Chris k

Pour répondre à vos questions: pourquoi n'est-ce pas possible? Je pense que ce n'est pas une exigence conventionnelle d'un SGBDM. Quelqu'un d'autre a-t-il déjà rencontré cela comme un problème? Je n'ai pas eu besoin de cette fonctionnalité auparavant. Cela étant dit, il y aura un compromis entre performance et disponibilité requise pour la mettre en œuvre.

  • Vous pouvez utiliser la méthode de Marian décrite dans les commentaires pour la mettre en œuvre, mais il y aura une performance touchée par les déclencheurs sur chaque insert.
  • Si la disponibilité n'est pas un problème, vous pouvez utiliser un CHECK constraint Pour vous assurer que l'identité ne frappe pas 999999. Une fois qu'elle le fait, la réensemne manuellement en utilisant DBCC checkident (comme mentionné par Marian), ou vous pouvez créer un travail d'agent SQL pour vérifier les intervalles et répercuter selon les besoins.
1
StanleyJohns