Почему простая команда 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 с пакетом обновления 2 (в ближайшее время будет обновлен до 2008 SP2).

Ответы:


15

Схема меняет его так долго, потому что вы присваиваете столбцу значение по умолчанию во время изменения и применяете его к столбцу без значения NULL, и он должен заполнить столбец более чем 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;

Надеемся, что это последнее обновление схемы будет выполнено быстро, как только все значения не будут равны NULL, и будет установлено NumericValueзначение по умолчанию.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.