it-swarm-eu.dev

Proč jednoduchý příkaz ALTER TABLE na tabulce s fulltextovým indexem trvá tak dlouho?

Mám velkou (~ 67 milionů řádků) tabulku název-hodnota, která má fulltextové indexování ve sloupci DataValue.

Pokud se pokusím spustit následující příkaz:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

Běží po dobu 1 hodiny 10 minut a stále se nedokončí v tabulce VisitorData, která obsahuje ~ 67 milionů řádků.

  1. Proč to trvá tak dlouho a nedokončí se?
  2. Co s tím mohu dělat?

Zde jsou další podrobnosti o tabulce:

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

Typy čekání, které se vyskytují během příkazu ALTER TABLE, Jsou LCK_M_SCH_M (Modifikace schématu) podle výsledků dotazu níže:

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

Pracuji s produkčními servery se systémem SQL Server 2005 SP 2 (brzy bude upgradován na 2008 SP2).

14
BobbyR-1of4

Schéma to změní tak dlouho, protože při změně přiřazujete sloupci výchozí hodnotu a vynucujete ji pomocí nullového sloupce a musí naplnit sloupec pro 60+ milionů řádků, což je neuvěřitelně nákladná operace. Nejsem si jistý, jaké jsou vaše požadavky na aplikaci, ale přístup, který by urychlil změnu schématu, je přidat jej do nulovatelného sloupce bez výchozí hodnoty a poté provést aktualizaci v dávkách tak, aby jako sloupec byla přiřazena hodnota 0. Po dokončení aktualizace můžete použít další změnu schématu a změnit tak sloupec na null a přiřadit výchozí hodnotu.

16

Indexování fulltextového textu je pravděpodobně pro váš problém irelevantní. Předchozí k serveru SQL Server 2012 ADD COLUMN NOT NULL DEFAULT ... je offline operace, která musí spustit aktualizaci a naplnit každý řádek novou výchozí hodnotou nově přidaného sloupce. V SQL Server 2012+ je operace mnohem rychlejší, viz Online non-NULL s přidáním sloupce hodnot v SQL Server 11 , protože aktualizuje pouze metadata tabulky a ve skutečnosti neaktualizuje žádné řádky.

Vaše ALTER TABLE je s největší pravděpodobností pomalý kvůli aktualizaci. Pamatujte, že protože se jedná o jednu transakci, bude vygenerován obrovský protokol a váš protokol pravděpodobně roste a bude se neustále rozšiřovat, protože se neustále rozšiřuje. Může to však být také pomalé kvůli obvyklému sporu: prohlášení nemusí být schopno získat zámek SCH-M na stole. Při pohledu na sys.dm_exec_requests by mělo ukázat, je-li tomu tak, wait_type a wait_resource sloupce by označovaly, zda je příkaz ALTER blokován nebo probíhá.

9
Remus Rusanu

Odpověď původně přidaná k otázce autorem:

Podle Jasonova odpověď jsem místo toho vydal následující aktualizaci:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Nakonec to provedlo, ale trvalo to 29 minut, 16 sekund. Samotná operace by měla být docela rychlá (pouze metadata), takže si představuji, že téměř celá ta doba byla strávena čekáním na získání nezbytného zámku LCK_M_SCH_M (Změna schématu).

S novým polem bit jsem mohl rychle přidat výchozí hodnotu do skriptu:

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

Momentálně nastavuji všechny NumericValue bity v tabulce pomocí uživatelem definované funkce (viz níže). Probíhá a trvá přibližně 1 minutu na každých 1 milion řádků v tabulce ~ 68 milionů řádků.

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

Jakmile je to hotové, mám v plánu provést finální úpravu schématu, aby se nový bitový sloupec stal null:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

Doufejme, že tato poslední aktualizace schématu bude spuštěna rychle, jakmile budou všechny hodnoty null a bude nastavena výchozí NumericValue.

0
user126897