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ů.
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).
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.
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á.
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
.