Utiliser des transactions dans un pool SQL dans Azure Synapse

Cet article contient des conseils d’implémentation de transactions et de développement de solutions dans un pool SQL.

À quoi s’attendre

Comme vous le savez, le pool SQL prend en charge les transactions dans le cadre de la charge de travail de l’entrepôt de données. Toutefois, pour que le pool SQL puisse être maintenu à grande échelle, certaines fonctionnalités sont limitées par rapport à SQL Server. Cet article identifie les différences.

Niveaux d’isolation des transactions

Le pool SQL implémente les transactions ACID. Par défaut, le niveau d'isolation de la prise en charge transactionnelle est READ UNCOMMITTED. Vous pouvez le remplacer par READ COMMITTED SNAPSHOT ISOLATION en activant l’option de base de données READ_COMMITTED_SNAPSHOT pour un pool SQL utilisateur lorsqu’il est connecté à la base de données MASTER.

Une fois activée, toutes les transactions de cette base de données sont exécutées sous READ COMMITTED SNAPSHOT ISOLATION et la définition de READ UNCOMMITTED au niveau de la session n'est pas honorée. Pour plus d'informations, consultez Options ALTER DATABASE SET (Transact-SQL).

Taille de la transaction

Une transaction de modification de données unique est limitée en taille. La limite est appliquée par distribution. Par conséquent, l’allocation totale peut être calculée en multipliant la limite par le nombre de distributions.

Pour évaluer approximativement le nombre maximal de lignes dans la transaction, divisez la limite de la distribution par la taille totale de chaque ligne. Pour les colonnes de longueur variable, pensez à prendre une longueur de colonne moyenne au lieu d’utiliser la taille maximale.

Dans le tableau ci-dessous, deux hypothèses ont été formulées :

  • Une distribution égale des données s’est produite
  • La longueur de ligne moyenne est de 250 octets

Deuxième génération

DWU Limite par distribution (Go) Nombre de distributions Taille de transaction MAX (Go) Nombre de lignes par distribution Nombre de lignes max par transaction
DW100c 1 60 60 4 000 000 240 000 000
DW200c 1.5 60 90 6 000 000 360 000 000
DW300c 2.25 60 135 9 000 000 540 000 000
DW400c 3 60 180 12 000 000 720 000 000
DW500c 3,75 60 225 15 000 000 900 000 000
DW1000c 7.5 60 450 30 000 000 1 800 000 000
DW1500c 11,25 60 675 45 000 000 2 700 000 000
DW2000c 15 60 900 60 000 000 3 600 000 000
DW2500c 18,75 60 1 125 75 000 000 4 500 000 000
DW3000c 22,5 60 1 350 90 000 000 5 400 000 000
DW5000c 37.5 60 2 250 150 000 000 9 000 000 000
DW6000c 45 60 2 700 180 000 000 10 800 000 000
DW7500c 56,25 60 3 375 225 000 000 13 500 000 000
DW10000c 75 60 4 500 300 000 000 18 000 000 000
DW15000c 112,5 60 6 750 450 000 000 27 000 000 000
DW30000c 225 60 13 500 900 000 000 54 000 000 000

Première génération

DWU Limite par distribution (Go) Nombre de distributions Taille de transaction MAX (Go) Nombre de lignes par distribution Nombre de lignes max par transaction
DW100 1 60 60 4 000 000 240 000 000
DW200 1.5 60 90 6 000 000 360 000 000
DW300 2.25 60 135 9 000 000 540 000 000
DW400 3 60 180 12 000 000 720 000 000
DW500 3,75 60 225 15 000 000 900 000 000
DW600 4.5 60 270 18 000 000 1 080 000 000
DW1000 7.5 60 450 30 000 000 1 800 000 000
DW1200 9 60 540 36 000 000 2 160 000 000
DW1500 11,25 60 675 45 000 000 2 700 000 000
DW2000 15 60 900 60 000 000 3 600 000 000
DW3000 22,5 60 1 350 90 000 000 5 400 000 000
DW6000 45 60 2 700 180 000 000 10 800 000 000

La limite de taille de transaction est appliquée par transaction ou opération. Elle n’est pas appliquée à toutes les transactions simultanées. Par conséquent, chaque transaction est autorisée à écrire cette quantité de données dans le journal.

Pour optimiser et réduire la quantité de données écrites dans le journal, consultez l’article Bonnes pratiques relatives aux transactions.

Avertissement

La taille de transaction maximale ne peut être obtenue que pour les tables distribuées HASH ou ROUND_ROBIN où la répartition des données est égale. Si la transaction écrit les données de manière asymétrique dans les distributions, alors la limite est susceptible d’être atteinte avant la taille de transaction maximale.

État des transactions

Le pool SQL utilise la fonction XACT_STATE() pour signaler une transaction non réussie, avec la valeur -2. Cette valeur signifie que la transaction a échoué et est marquée pour une restauration uniquement.

Notes

L’association de la valeur -2 à la fonction XACT_STATE afin de signaler l’échec d’une transaction constitue un comportement différent par rapport à SQL Server. SQL Server utilise la valeur -1 pour représenter une transaction non validable. De plus, il peut tolérer la présence de certaines erreurs au sein d’une transaction sans pour autant signaler que cette dernière ne peut pas être validée. Par exemple, SELECT 1/0 entraîne une erreur, mais ne fait pas passer la transaction à l’état non validable.

Par ailleurs, SQL Server autorise également les lectures dans une transaction non validable. En revanche, le pool SQL ne le permet pas. Si une erreur se produit dans une transaction de pool SQL, celle-ci passe automatiquement à l’état -2 ; il n’est pas possible d’effectuer d’autres instructions SELECT tant qu’elle n’a pas été restaurée.

Vous devez donc impérativement vérifier si le code de votre application utilise XACT_STATE(), car vous pouvez avoir besoin de modifier le code.

Dans SQL Server par exemple, vous pourriez rencontrer une transaction de ce type :

SET NOCOUNT ON;
DECLARE @xact_state smallint = 0;

BEGIN TRAN
    BEGIN TRY
        DECLARE @i INT;
        SET     @i = CONVERT(INT,'ABC');
    END TRY
    BEGIN CATCH
        SET @xact_state = XACT_STATE();

        SELECT  ERROR_NUMBER()    AS ErrNumber
        ,       ERROR_SEVERITY()  AS ErrSeverity
        ,       ERROR_STATE()     AS ErrState
        ,       ERROR_PROCEDURE() AS ErrProcedure
        ,       ERROR_MESSAGE()   AS ErrMessage
        ;

        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRAN;
            PRINT 'ROLLBACK';
        END

    END CATCH;

IF @@TRANCOUNT >0
BEGIN
    PRINT 'COMMIT';
    COMMIT TRAN;
END

SELECT @xact_state AS TransactionState;

Le code précédent génère le message d’erreur suivant :

Msg 111233, Level 16, State 1, Line 1 111233; La transaction active a été abandonnée. Les modifications en attente ont été restaurées. La cause de ce problème est qu’une transaction à l’état restauration uniquement n’est pas explicitement restaurée avant une instruction DDL, DML ou SELECT.

Vous n’obtiendrez pas la sortie des fonctions ERROR_* non plus.

Dans le pool SQL, le code doit être légèrement modifié :

SET NOCOUNT ON;
DECLARE @xact_state smallint = 0;

BEGIN TRAN
    BEGIN TRY
        DECLARE @i INT;
        SET     @i = CONVERT(INT,'ABC');
    END TRY
    BEGIN CATCH
        SET @xact_state = XACT_STATE();

        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRAN;
            PRINT 'ROLLBACK';
        END

        SELECT  ERROR_NUMBER()    AS ErrNumber
        ,       ERROR_SEVERITY()  AS ErrSeverity
        ,       ERROR_STATE()     AS ErrState
        ,       ERROR_PROCEDURE() AS ErrProcedure
        ,       ERROR_MESSAGE()   AS ErrMessage
        ;
    END CATCH;

IF @@TRANCOUNT >0
BEGIN
    PRINT 'COMMIT';
    COMMIT TRAN;
END

SELECT @xact_state AS TransactionState;

Le comportement attendu est maintenant examiné. L’erreur dans la transaction est gérée, et les fonctions ERROR_* fournissent les valeurs attendues.

La seule chose qui a changé est que l’opération ROLLBACK de la transaction doit se produire avant la lecture des informations sur l’erreur, dans le bloc CATCH.

Fonction Error_Line()

Il est également important de signaler que le pool SQL n’implémente ni ne prend en charge la fonction ERROR_LINE(). Si elle figure dans votre code, vous devez la supprimer pour respecter les exigences du pool SQL.

Placez plutôt des libellés de requête dans votre code pour implémenter les fonctionnalités équivalentes. Pour plus d’informations, consultez l’article LABEL.

Utilisation des paramètres THROW et RAISERROR

THROW est l’implémentation la plus moderne du déclenchement d’exceptions dans le pool SQL, mais RAISERROR est également pris en charge. Il existe cependant quelques différences, qu’il est préférable de prendre en compte.

  • Les numéros associés aux messages d’erreur définis par l’utilisateur ne peuvent pas se trouver dans la plage de valeurs allant de 100 000 à 150 000 dans le cas du paramètre THROW.
  • Les messages d’erreurs associés au paramètre RAISERROR sont définis sur la valeur fixe de 50 000.
  • L’utilisation de l’élément sys.messages n’est pas prise en charge.

Limites

En ce qui concerne les transactions, le pool SQL présente quelques restrictions supplémentaires.

Les voici :

  • Les transactions distribuées ne sont pas acceptées.
  • Les transactions imbriquées ne sont pas autorisées.
  • Les points de sauvegarde ne sont pas acceptés.
  • Transactions sans nom
  • Transactions sans marquage
  • Aucune prise en charge de DDL comme CREATE TABLE dans une transaction définie par l’utilisateur

Étapes suivantes

Pour plus d’informations sur l’optimisation des transactions, consultez Bonnes pratiques relatives aux transactions. Pour plus d’informations sur les autres meilleures pratiques en matière de pool SQL, consultez Meilleures pratiques pour les pools SQL.