Perché il semplice comando ALTER TABLE impiega così tanto tempo sulla tabella con indice full-text?


14

Ho una grande tabella (~ 67 milioni di righe) nome-valore che ha l'indicizzazione full-text su DataValue colonna.

Se provo a eseguire il comando seguente:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

Funziona per 1 ora e 10 minuti e non viene ancora completato su una VisitorDatatabella che contiene ~ 67 milioni di righe.

  1. Perché questo richiede così tanto tempo e non si completa?
  2. Cosa posso fare al riguardo?

Ecco altri dettagli sulla tabella:

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

I tipi di attesa che si verificano durante il ALTER TABLEcomando sono LCK_M_SCH_M(modifica dello schema), secondo i risultati della query di seguito:

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

Sto lavorando con server di produzione che eseguono SQL Server 2005 SP 2 (che presto verrà aggiornato a 2008 SP2).

Risposte:


15

Lo schema lo modifica impiegando così tanto tempo perché stai assegnando un valore predefinito alla colonna durante la modifica e applicandolo con una colonna non nullable, e deve popolare la colonna per oltre 60 milioni di righe, il che è un'operazione incredibilmente costosa. Non sono sicuro di quali siano i requisiti dell'applicazione ma un approccio che renderebbe più veloce la modifica dello schema consiste nell'aggiungerlo come colonna nullable senza valore predefinito e quindi eseguire un aggiornamento in batch per assegnare 0 come valore per la colonna. Al termine dell'aggiornamento, è possibile applicare un'altra modifica dello schema per modificare la colonna in non annullabile e assegnare il valore predefinito.


9

L'indicizzazione full-text è, probabilmente, irrilevante per il tuo problema. Precedentemente a SQL Server 2012 ADD COLUMN NOT NULL DEFAULT ...è un'operazione offline che deve eseguire un aggiornamento e popolare ogni riga con il nuovo valore predefinito della colonna appena aggiunta. In SQL Server 2012+, l'operazione è molto più veloce, vedi colonna Non-NULL online con valori aggiunti in SQL Server 11 in quanto aggiorna solo i metadati della tabella e non aggiorna effettivamente alcuna riga.

Molto ALTER TABLEprobabilmente è lento a causa dell'aggiornamento. Ricorda, poiché si tratta di una singola transazione, verrà generato un registro enorme e il tuo registro probabilmente sta crescendo ora e viene costantemente azzerato man mano che si espande. Tuttavia, potrebbe anche essere lento a causa di una normale contesa: l'affermazione potrebbe non essere in grado di acquisire il blocco SCH-M sul tavolo. Guardando sys.dm_exec_requestsdovrebbe mostrare se questo è il caso, le colonne wait_typee wait_resourceindicano se l' ALTERistruzione è bloccata o sta facendo progressi.


0

Risposta originariamente aggiunta alla domanda dal suo autore:

In base alla risposta di Jason , ho invece pubblicato il seguente aggiornamento:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Questo alla fine fu eseguito, ma impiegò 29 minuti, 16 secondi. L'operazione in sé dovrebbe essere piuttosto rapida (solo metadati), quindi immagino che quasi tutto quel tempo sia stato trascorso in attesa di acquisire il necessarioLCK_M_SCH_M blocco (modifica dello schema).

Con il nuovo bitcampo attivo, sono stato in grado di aggiungere rapidamente il valore predefinito tramite lo script:

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

Sono in procinto di impostare tutti i NumericValuebit nella tabella utilizzando una funzione definita dall'utente (vedere di seguito). È in corso e richiede circa 1 minuto ogni 1 milione di righe nella tabella ~ 68 milioni di righe.

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

Una volta completato, ho intenzione di eseguire la regolazione dello schema finale per rendere la nuova colonna di bit non nulla:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

Eventualmente, l'ultimo aggiornamento dello schema verrà eseguito rapidamente una volta che tutti i valori sono non nulli e l' NumericValueimpostazione predefinita è attiva.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.