it-swarm.com.de

Warum dauert der einfache Befehl ALTER TABLE für Tabellen mit Volltextindex so lange?

Ich habe eine große (~ 67 Millionen Zeilen) Name-Wert-Tabelle mit Volltextindizierung für die Spalte DataValue.

Wenn ich versuche, den folgenden Befehl auszuführen:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

Es läuft 1 Stunde 10 Minuten und wird in einer VisitorData -Tabelle, die ~ 67 Millionen Zeilen enthält, immer noch nicht abgeschlossen.

  1. Warum dauert das so lange und dauert nicht an?
  2. Was kann ich tun?

Hier sind weitere Einzelheiten zur Tabelle:

CREATE TABLE [dbo].[VisitorData](
            [VisitorID] [int] NOT NULL,
            [DataName] [varchar](80) NOT NULL,
            [DataValue] [nvarchar](3800) NOT NULL,
            [EncryptedDataValue] [varbinary](max) NULL,
            [VisitorDataID] [int] IDENTITY(1,1) NOT NULL, 
CONSTRAINT [PK_VisitorData_VisitorDataID] PRIMARY KEY CLUSTERED (
            [VisitorDataID] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY], 
CONSTRAINT [UNQ_VisitorData_VisitorId_DataName] UNIQUE NONCLUSTERED (
            [VisitorID] ASC,
            [DataName] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[VisitorData]
ADD  CONSTRAINT [UNQ_VisitorData_VisitorDataID] UNIQUE NONCLUSTERED (

[VisitorDataID] 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 [PRIMARY]
GO

ALTER TABLE [dbo].[VisitorData]
    WITH CHECK ADD
        CONSTRAINT [FK_VisitorData_Visitors] FOREIGN KEY([VisitorID])
        REFERENCES [dbo].[Visitors] ([VisitorID])
GO

ALTER TABLE [dbo].[VisitorData]
    CHECK CONSTRAINT [FK_VisitorData_Visitors] GO

CREATE FULLTEXT CATALOG DBName_VisitorData_Catalog WITH ACCENT_SENSITIVITY = ON
CREATE FULLTEXT INDEX ON VisitorData ( DataValue Language 1033 )
    KEY INDEX UNQ_VisitorData_VisitorDataID
    ON DBName_VisitorData_Catalog
    WITH CHANGE_TRACKING AUTO
GO

Die Wartetypen, die während des ALTER TABLE Befehl sind LCK_M_SCH_M (Schemaänderung) gemäß den folgenden Abfrageergebnissen:

select * from  sys.dm_os_waiting_tasks

waiting_task_address    session_id exec_context_id wait_duration_ms     wait_type            resource_address       blocking_task_address   blocking_session_id blocking_exec_context_id resource_description
--------------------             ----------     --------------- --------------------              -------------------- ------------------             ---------------------            -------------------        ------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0x0000000000B885C8   54               0                   112695                            LCK_M_SCH_M   0x00000000802DF600 0x000000000054E478     25                            0                                         objectlock lockPartition=0 objid=834102012 subresource=FULL dbid=5 id=lock438a02e80 mode=IS associatedObjectId=834102012
0x0000000000B885C8   54               0                   112695                            LCK_M_SCH_M   0x00000000802DF600 0x00000000088AB048    23                            0                                         objectlock lockPartition=0 objid=834102012 subresource=FULL dbid=5 id=lock438a02e80 mode=IS associatedObjectId=834102012

Ich arbeite mit Produktionsservern, auf denen SQL Server 2005 ausgeführt wird SP 2 (wird bald auf 2008 SP2 aktualisiert).

14
BobbyR-1of4

Die Schemaänderung dauert so lange, weil Sie der Spalte während der Änderung einen Standardwert zuweisen und diesen mit einer nicht nullbaren Spalte erzwingen. Außerdem muss die Spalte mit mehr als 60 Millionen Zeilen gefüllt werden. Dies ist eine unglaublich teure Operation. Ich bin nicht sicher, was Ihre Anwendungsanforderungen sind, aber ein Ansatz, der die Schemaänderung beschleunigen würde, besteht darin, es als nullfähige Spalte ohne Standardwert hinzuzufügen und dann eine Aktualisierung in Stapeln durchzuführen, um 0 als Wert für die Spalte zuzuweisen. Nachdem Ihre Aktualisierung abgeschlossen ist, können Sie eine weitere Schemaänderung anwenden, um die Spalte in nicht nullbar zu ändern und den Standardwert zuzuweisen.

16

Die Volltextindizierung ist für Ihr Problem wahrscheinlich irrelevant. Vor SQL Server 2012 war das ADD COLUMN NOT NULL DEFAULT ... ist eine Offline-Operation, bei der ein Update ausgeführt und jede Zeile mit dem neuen Standardwert der neu hinzugefügten Spalte gefüllt werden muss. In SQL Server 2012+ ist der Vorgang viel schneller (siehe Online nicht NULL mit Wertespalte in SQL Server 11 hinzufügen , da nur die Metadaten der Tabelle aktualisiert werden und tatsächlich keine Zeilen aktualisiert werden.

Ihre ALTER TABLE ist aufgrund des Updates höchstwahrscheinlich langsam. Denken Sie daran, da dies eine einzelne Transaktion ist, wird ein riesiges Protokoll generiert, und Ihr Protokoll wächst wahrscheinlich jetzt und wird bei seiner Erweiterung ständig auf Null gesetzt. Aufgrund gewöhnlicher Konflikte kann es jedoch auch langsam sein: Die Anweisung kann möglicherweise die SCH-M-Sperre für den Tisch nicht abrufen. Anschauen sys.dm_exec_requests sollte zeigen, ob dies der Fall ist, das wait_type und wait_resource Spalten würden anzeigen, ob die Anweisung ALTER blockiert ist oder Fortschritte macht.

9
Remus Rusanu

Antwort, die ursprünglich vom Autor zu der Frage hinzugefügt wurde:

Gemäß Jasons Antwort habe ich stattdessen das folgende Update veröffentlicht:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Dies wurde schließlich ausgeführt, dauerte jedoch 29 Minuten und 16 Sekunden. Die Operation selbst sollte ziemlich schnell sein (nur Metadaten), daher stelle ich mir vor, dass fast die gesamte Zeit darauf gewartet wurde, das notwendige LCK_M_SCH_M (Schemamodifikation) sperren.

Mit dem neuen Feld bit konnte ich schnell den Standardwert über das Skript hinzufügen:

ALTER TABLE VisitorData ADD
CONSTRAINT DF_VisitorData_NumericValue DEFAULT(0) FOR NumericValue;

Ich bin gerade dabei, alle NumericValue Bits in der Tabelle mithilfe einer benutzerdefinierten Funktion zu setzen (siehe unten). Es wird ausgeführt und dauert ungefähr 1 Minute pro 1 Million Zeilen in der ~ 68 Millionen-Zeilentabelle.

WITH RD_CTE (VisitorD, DataName) 
AS
(
    SELECT TOP 10000 VisitorD, DataName
    FROM VisitorData WITH (NOLOCK)
    WHERE NumericValue IS NULL  
)
UPDATE VisitorData
SET NumericValue = CASE WHEN dbo.ufn_IsReallyNumeric(rd.DataValue) = 1 THEN 1 ELSE 0 END
FROM VisitorData rd WITH (NOLOCK) 
INNER JOIN RD_CTE rdc WITH (NOLOCK) ON rd.VisitorD = rdc.VisitorD  AND rd.DataName = rdc.DataName

GO 6800

Sobald dies abgeschlossen ist, plane ich, die endgültige Schemaanpassung auszuführen, damit diese neue Bitspalte nicht null ist:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

Hoffentlich wird dieses letzte Schema-Update schnell ausgeführt, sobald alle Werte nicht null sind und der Standardwert NumericValue vorhanden ist.

0
user126897