none
sp_rename in einer Transaktion RRS feed

  • Frage

  • Hallo, 

    ich stelle Daten in SQL Server Datenbanktabellen zur Verfügung, die regelmäßig aus einer DB2 kopiert werden. Damit es dabei zu keinen Unterbrechungen in der Datenbereitstellung gibt, werden die Daten zunächst in temporäre Tabellen kopiert, bevor die temporären Tabellen mittels sp_rename umbenannt werden. Das funktioniert bislang auch immer (bei den unterschiedlichsten Kunden). Nun gibt es bei einem Kunden aber das Problem, dass die Standard-Warnung von sp_rename zu einem Rollback meiner Transktion führt. Hat hierzu jemand eine Idee?

    SQL Server Version ist 

    Microsoft SQL Server 2014 (SP2-GDR) (KB4019093) - 12.0.5207.0 (X64) 
    Jul  3 2017 02:25:44 
    Copyright (c) Microsoft Corporation
    Standard Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

    Mein Skript sieht wie folgt aus:

    -- Beginne eine neue Datenbanktransaktion, so dass während der Ausführung keine 
    -- Daten gelesen werden können und im Fehlerfall ein Rollback möglich ist.
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    BEGIN TRANSACTION ReleaseTable WITH MARK N'RELEASE_DV_PARTNER';
    BEGIN TRY
        -- Lösche nun die Vorgängertabelle mit älterem Datenbestand.
        IF OBJECT_ID('dbo.DV_PARTNER','U') IS NOT NULL
            DROP TABLE [dbo].[DV_PARTNER];
        -- Ersetze die Vorgängertabelle durch die neu befüllte Zieltabelle.
        EXECUTE sp_rename 'TMP_PARTNER', 'DV_PARTNER';
        -- Benenne den Primärschlüssel um
        ALTER TABLE [dbo].[DV_PARTNER] DROP CONSTRAINT [PK_TMP_PARTNER];
        ALTER TABLE [dbo].[DV_PARTNER] ADD CONSTRAINT [PK_DV_PARTNER] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [INDEX]
        -- Lösche temporäre Tabellen und Sichten
        IF OBJECT_ID('dbo.TMP_VERSICHERTEPERSON_FAMILIENVERSICHERTER','U') IS NOT NULL
            DROP TABLE [dbo].[TMP_VERSICHERTEPERSON_FAMILIENVERSICHERTER];
        IF OBJECT_ID('dbo.TMP_VERSICHERTEPERSON_MITGLIED','U') IS NOT NULL
            DROP TABLE [dbo].[TMP_VERSICHERTEPERSON_MITGLIED];
        IF OBJECT_ID('dbo.TMP_VERSICHERTEPERSON_STORNIERT','U') IS NOT NULL
            DROP TABLE [dbo].[TMP_VERSICHERTEPERSON_STORNIERT];
        IF OBJECT_ID('dbo.TMP_VERSICHERTEPERSON','V') IS NOT NULL
            DROP VIEW [dbo].[TMP_VERSICHERTEPERSON];
        -- Bestätige die Transaktion, falls bis hierher kein Fehler auftrat.
        COMMIT TRANSACTION ReleaseTable;
        SELECT 0;
    END TRY
    BEGIN CATCH
        -- Stelle die Ursprungssitutation im Fehlerfall wieder her. Die Vorgänger-
        -- tabelle mit dem älteren Datenbestand bleibt so erhalten.
        ROLLBACK TRANSACTION ReleaseTable;
        RAISERROR('Die Tabelle DV_PARTNER konnte nicht freigegeben werden.',16,1);
    END CATCH

    Die Meldung, welche dann auch zum Betreten des CATCH Blocks führt, ist:

    Vorsicht: Wenn Sie Teile eines Objektnamens ändern, werden Skripts und gespeicherte Prozeduren möglicherweise funktionsunfähig.

    Grüße,

    Michael

    Mittwoch, 29. August 2018 16:03

Antworten

  • Hallo Michael,

    die "Fehlermeldung" ist keine wirkliche Fehlermeldung sondern lediglich eine Warnung. Wie kommst Du darauf, dass der Block tatsächlich den CATCH-Block ausführt?

    Ich habe - in vereinfachter Form - das ganze mal ausprobiert:

    USE CustomerOrders;
    GO
    BEGIN TRANSACTION
    BEGIN TRY
    	EXEC sp_rename
    		@objname = N'dbo.newCustomers',
    		@objtype = N'OBJECT',
    		@newname = N'Customers';
    END TRY
    BEGIN CATCH
    	SELECT 'Voll der Fehler...';
    END CATCH;
    GO
    COMMIT TRANSACTION;
    GO

    Die Transaktion wird ganz normal beendet. Die "Fehlermeldung" ist message_id 15477. Diese Meldung ist lediglich ein Hinweis, der innerhalb von sp_rename erzeugt wird, um darauf hinzuweisen, dass ein Umbenennen dazu führen kann, dass Prozeduren, Views, etc. das Objekt nicht mehr ansprechen können.

    In der Prozedur sp_rename weist Microsoft selbst auf diesen Umstand hin...

    "WITH DEFERRED RESOLUTION, sql_dependencies  IS NOT VERY ACCURATE, SO WE ALSO RAISE THIS WARNING **UNCONDITIONALLY**, EVEN FOR NON-OBJECT RENAMES"

    und generiert den entsprechenden Fehler. Um den Hintergrund zu verstehen, muss man den Aufruf in sp_rename etwas genauer untersuchen:

    raiserror(15477,-1,-1)

    Hierbei ist vor allen Dingen der zweite Parameter (-1) zu beachten. Mit Hilfe von -1 wird die Meldung mit dem Schweregrad ausgegeben, der in sys.messages für die entsprechende Message_id angeben ist (für 15477 ist das der Wert 10!)

    Die von RAISERROR generierten Fehler funktionieren genauso wie Fehler, die vom Code der Datenbank-Engine generiert werden. Die von RAISERROR angegebenen Werte werden von den Systemfunktionen ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER, ERROR_PROCEDURE, ERROR_SEVERITY, ERROR_STATE und @@ ERROR gemeldet.

    Wenn RAISERROR mit einem Schweregrad von 11 oder höher in einem TRY-Block ausgeführt wird, überträgt es die Steuerung an den zugeordneten CATCH-Block. Der Fehler wird an den Aufrufer zurückgegeben, wenn RAISERROR ausgeführt wird:

    Somit sollte der CATCH-Block nicht erreicht werden - zumindest nicht durch sp_rename.


    Uwe Ricken (Blog | Twitter)
    Microsoft Certiifed Master - SQL Server 2008
    Microsoft Certified Solution Master - CHARTER Data Platform
    Microsoft Certified Solution Expert - Data Platform
    db Berater GmbH
    Microsoft SQL Server Blog (german only)


    Donnerstag, 30. August 2018 16:19

Alle Antworten

  • Du kannst es damit versuchen:

    https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-warnings-transact-sql?view=sql-server-2017

    Den Status kannst du aktuell per Select abfragen, die Warnings ggf. abschalten, die Aktion ausfhren und die Warnings ggf. wieder einschalten.
    In der Doku finde ich nichts auf die Schnelle, ob das sitzungsspezifisch oder sogar transaktionsspezifisch ist, also nach Disconnect oder Commit/Rollback zurückgesetzt wird.

    Mittwoch, 29. August 2018 16:10
  • Am 29.08.2018 schrieb sp_rename in einer Transaktion ausführen:

    Microsoft SQL Server 2014 (SP2-GDR) (KB4019093) - 12.0.5207.0 (X64) 
    Jul  3 2017 02:25:44 

    Dein SQL Server ist nicht mehr aktuell, du solltest das letzte CU
    installieren. Details zu den Builds gibt es hier:
    https://buildnumbers.wordpress.com/sqlserver/

    Servus
    Winfried


    WSUS Package Publisher: http://wsuspackagepublisher.codeplex.com/
    HowTos zum WSUS Package Publisher http://www.wsus.de/wpp
    GPO's: http://www.gruppenrichtlinien.de
    NNTP-Bridge für MS-Foren: http://communitybridge.codeplex.com/
    GP-PACK - PRIVACY AND TELEMETRIE: http://www.gp-pack.com/

    Mittwoch, 29. August 2018 16:33
  • Hallo,

    gute Idee, die ich auch direkt ausprobiert habe. Aber weder vor Transaktionsbeginn, noch unmittelbar vor dem sp_rename hat SET ANSI_WARNINGS OFF eine Auswirkung auf mein Problem.

    Grüße, Michael

    Donnerstag, 30. August 2018 07:18
  • Ich habe hier eine Diskussion gefunden, dass man dies nicht ausschalten kann:
    https://social.technet.microsoft.com/Forums/sqlserver/en-US/bb121a87-2681-4a9f-b38a-6870657c95e4/sprename-suppress-warning-message?forum=transactsql

    Wofür die Routine dann gut ist, entzieht sich mir.
    https://docs.microsoft.com/de-de/sql/relational-databases/system-stored-procedures/sp-rename-transact-sql?view=sql-server-2017

    Auf die Problem wird hingewiesen, allerdings entzieht sich mir, wie ich dann die Routine anwenden soll.
    Umgekehrt könnte es ja auch sein, dass man speziell bei diesem Warning trotzdem einen Commit machen kann um die Umbenennung wirksam werden zu lassen.

    Mittels Error_Message() kannst du ja darauf prüfen:
    https://docs.microsoft.com/de-de/sql/t-sql/functions/error-message-transact-sql?view=sql-server-2017

    Alternativ kannst du ja auch direkt den Rename verwenden (Version?):
    https://docs.microsoft.com/de-de/sql/t-sql/statements/rename-transact-sql?view=aps-pdw-2016-au7

    Donnerstag, 30. August 2018 10:02
  • Hallo Michael,

    die "Fehlermeldung" ist keine wirkliche Fehlermeldung sondern lediglich eine Warnung. Wie kommst Du darauf, dass der Block tatsächlich den CATCH-Block ausführt?

    Ich habe - in vereinfachter Form - das ganze mal ausprobiert:

    USE CustomerOrders;
    GO
    BEGIN TRANSACTION
    BEGIN TRY
    	EXEC sp_rename
    		@objname = N'dbo.newCustomers',
    		@objtype = N'OBJECT',
    		@newname = N'Customers';
    END TRY
    BEGIN CATCH
    	SELECT 'Voll der Fehler...';
    END CATCH;
    GO
    COMMIT TRANSACTION;
    GO

    Die Transaktion wird ganz normal beendet. Die "Fehlermeldung" ist message_id 15477. Diese Meldung ist lediglich ein Hinweis, der innerhalb von sp_rename erzeugt wird, um darauf hinzuweisen, dass ein Umbenennen dazu führen kann, dass Prozeduren, Views, etc. das Objekt nicht mehr ansprechen können.

    In der Prozedur sp_rename weist Microsoft selbst auf diesen Umstand hin...

    "WITH DEFERRED RESOLUTION, sql_dependencies  IS NOT VERY ACCURATE, SO WE ALSO RAISE THIS WARNING **UNCONDITIONALLY**, EVEN FOR NON-OBJECT RENAMES"

    und generiert den entsprechenden Fehler. Um den Hintergrund zu verstehen, muss man den Aufruf in sp_rename etwas genauer untersuchen:

    raiserror(15477,-1,-1)

    Hierbei ist vor allen Dingen der zweite Parameter (-1) zu beachten. Mit Hilfe von -1 wird die Meldung mit dem Schweregrad ausgegeben, der in sys.messages für die entsprechende Message_id angeben ist (für 15477 ist das der Wert 10!)

    Die von RAISERROR generierten Fehler funktionieren genauso wie Fehler, die vom Code der Datenbank-Engine generiert werden. Die von RAISERROR angegebenen Werte werden von den Systemfunktionen ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER, ERROR_PROCEDURE, ERROR_SEVERITY, ERROR_STATE und @@ ERROR gemeldet.

    Wenn RAISERROR mit einem Schweregrad von 11 oder höher in einem TRY-Block ausgeführt wird, überträgt es die Steuerung an den zugeordneten CATCH-Block. Der Fehler wird an den Aufrufer zurückgegeben, wenn RAISERROR ausgeführt wird:

    Somit sollte der CATCH-Block nicht erreicht werden - zumindest nicht durch sp_rename.


    Uwe Ricken (Blog | Twitter)
    Microsoft Certiifed Master - SQL Server 2008
    Microsoft Certified Solution Master - CHARTER Data Platform
    Microsoft Certified Solution Expert - Data Platform
    db Berater GmbH
    Microsoft SQL Server Blog (german only)


    Donnerstag, 30. August 2018 16:19
  • Hallo Winfried,

    danke für Deine Idee. Leider hat ein Update auf CU13 keine Veränderung gebracht.

    BG Michael

    Freitag, 7. September 2018 13:22
  • Hallo Uwe,

    wie ich darauf komme, dass der CATCH Block angesprungen wird? Ganz einfach, ich erhalte diese Meldung, die nur von "meinem" CATCH Block ausgegeben wird:

    Vorsicht: Wenn Sie Teile eines Objektnamens ändern, werden Skripts und gespeicherte Prozeduren möglicherweise funktionsunfähig.
    Meldung 50000, Ebene 16, Status 1, Zeile 31
    Die Tabelle DV_PARTNER konnte nicht freigegeben werden.

    Üblicherweise wird der auch bei der Warnung 15477 nicht angesprungen, nur bei einem SQL Server System eines Kunden ist das nun mal so. Da ich schon gefühlt zehn verschiedene SQL Server Versionen ohne Probleme genutzt habe, vermute ich bestimmte System- oder Kontoeinstellungen auf dem SQL Server, die das Verhalten zu verantworten haben.

    BG Michael

    Freitag, 7. September 2018 13:26
  • Hallo zusammen,

    die Datenbank wurde vom Kunden mit dem Wiederherstellungsmodell "Vollständig" angelegt, statt "Einfach", wie von mir erwartet. Demnach und weil die Dateigruppe PRIMARY von der Größe beschränkt ist, wurde tatsächlich wegen der Neuerstellung des PRIMARY KEY ein Fehler ausgelöst, nicht etwa durch die Warnung aus sp_rename. Uwe hat also vollkommen recht, das war überhaupt nicht der Grund.

    Sinnvoller als

        -- Benenne den Primärschlüssel um
            ALTER TABLE [dbo].[DV_PARTNER] DROP CONSTRAINT [PK_TMP_PARTNER];
             ALTER TABLE [dbo].[DV_PARTNER] ADD CONSTRAINT [PK_DV_PARTNER] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [INDEX]

    ist ohnehin

        -- Benenne den Primärschlüssel um
        EXECUTE sp_rename N'TMP_PARTNER.PK_TMP_PARTNER', N'PK_DV_PARTNER', N'INDEX';

    Danke an alle und schönes Wochenende.

    Michael

    Freitag, 7. September 2018 14:37