Чому проста команда ALTER TABLE займає стільки часу на столі з повнотекстовим покажчиком?


14

У мене є велика (~ 67 мільйонів рядків) таблиця значень імен, яка має повнотекстову індексацію на DataValueстовпці.

Якщо я спробую виконати таку команду:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

Він працює 1 годину 10 хвилин і досі не завершується на VisitorDataтаблиці, що містить ~ 67 мільйонів рядків.

  1. Чому це займає так довго і не закінчується?
  2. Що я можу з цим зробити?

Ось докладніші відомості про таблицю:

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

Типи очікування, які виникають під час ALTER TABLEкоманди, є LCK_M_SCH_M(модифікація схеми) відповідно до наведених нижче результатів запиту:

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

Я працюю з виробничими серверами, на яких працює SQL Server 2005 SP 2 (незабаром буде оновлено до SP2 2008 року).

Відповіді:


16

Схема змінює його так довго, тому що ви призначаєте стовпець за замовчуванням під час зміни та застосовуєте його до стовпця, що не зводиться нанівець, і він повинен заповнити стовпчик на 60+ мільйонів рядків, що є надзвичайно дорогою операцією. Я не впевнений, які ваші вимоги до програми, але підхід, який би прискорив зміну схеми, полягає в тому, щоб додати її у стовпчиковий стовпчик без значення за замовчуванням, а потім виконати оновлення партіями, щоб призначити 0 як значення стовпця. Після завершення оновлення ви можете застосувати іншу зміну схеми, щоб змінити стовпець на нерегульований і призначити значення за замовчуванням.


9

Повнотекстова індексація, ймовірно, не має значення для вашої проблеми. Попередня SQL Server 2012 ADD COLUMN NOT NULL DEFAULT ...- це офлайн-операція, яка повинна запустити оновлення та заповнити кожну рядок новим значенням за замовчуванням щойно доданого стовпця. У SQL Server 2012+ операція відбувається набагато швидше, дивіться Інтернет-не-NULL зі стовпцем значень, доданим у SQL Server 11, оскільки він оновлює лише метадані таблиці та фактично не оновлює жодних рядків.

Ви ALTER TABLE, швидше за все, повільні через оновлення. Пам'ятайте, оскільки це єдина транзакція, буде створено величезний журнал, і ваш журнал, ймовірно, зростає зараз і буде постійно нульовим, коли він розширюється. Однак це може бути повільним через звичайні суперечки: заява може не мати змогу придбати замок SCH-M на столі. Дивлячись на, sys.dm_exec_requestsслід вказати, чи це так, wait_typeі wait_resourceстовпці вказуватимуть, якщо ALTERоператор заблокований чи прогресує.


0

Відповідь, оригінально додану на питання її автором:

Відповідно до відповіді Джейсона , я замість цього видав таке оновлення:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Це нарешті виконали, але зайняли 29 хвилин, 16 секунд. Сама операція повинна бути досить швидкою (лише метадані), тому я думаю, що майже весь цей час було витрачено в очікуванні придбання необхідного LCK_M_SCH_Mблокування (модифікація схеми).

Зі своїм новим bitполем я зміг швидко додати до нього значення за замовчуванням за допомогою сценарію:

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

Зараз я встановлюю всі NumericValueбіти таблиці за допомогою визначеної користувачем функції (див. Нижче). Він триває і займає приблизно 1 хвилину на кожні 1 мільйон рядків у таблиці ~ 68 мільйонів рядків.

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

Як тільки це буде завершено, я планую запустити остаточне коригування схеми, щоб зробити цей новий бітовий стовпець ненульовим:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

Будемо сподіватися, що останнє оновлення схеми запуститься швидко, коли всі значення будуть ненулевими та встановлено NumericValueза замовчуванням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.