it-swarm.it

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

Ho una grande tabella nome-valore (~ 67 milioni di righe) con indicizzazione full-text sulla colonna DataValue.

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 tabella VisitorData 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 TABLE command are 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).

14
BobbyR-1of4

Lo schema lo modifica così a lungo perché si sta 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, 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.

16

L'indicizzazione full-text è, probabilmente, irrilevante per il tuo problema. Precedente su SQL Server 2012 il 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, vedere Non-NULL online con colonna valori in SQL Server 11 poiché aggiorna solo i metadati della tabella e non aggiorna effettivamente alcuna riga.

Il tuo ALTER TABLE molto probabilmente è 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'istruzione potrebbe non essere in grado di acquisire il blocco SCH-M sul tavolo. Guardando sys.dm_exec_requests dovrebbe mostrare se questo è il caso, il wait_type e wait_resource colonne indica se l'istruzione ALTER è bloccata o sta avanzando.

9
Remus Rusanu

Risposta originariamente aggiunta alla domanda dal suo autore:

Come da 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 necessario LCK_M_SCH_M blocco (modifica dello schema).

Con il nuovo campo bit installato, 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 bit NumericValue 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;

Si spera che questo ultimo aggiornamento dello schema verrà eseguito rapidamente una volta che tutti i valori sono non nulli e il valore predefinito NumericValue è attivo.

0
user126897