フルテキストインデックスのあるテーブルで、単純なALTER TABLEコマンドが非常に長い時間がかかるのはなぜですか?


14

列にフルテキストインデックスが作成された大きな名前(〜6700万行)の名前と値のテーブルがありDataValueます。

次のコマンドを実行しようとすると:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

1時間10分間実行されVisitorDataますが、約6,700万行を含むテーブルでは完了しません。

  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を実行している運用サーバーで作業しています(すぐに2008 SP2にアップグレードされます)。

回答:


15

スキーマは、変更中に列にデフォルト値を割り当て、それをヌル不可列で強制しているため、非常に時間がかかり、列に6000万行以上を投入する必要があり、これは非常に高価な操作です。アプリケーションの要件がわからないが、スキーマの変更を高速化するアプローチは、デフォルト値を持たないnull値の列として追加し、バッチの更新を実行して列の値として0を割り当てることです。更新が完了したら、別のスキーマの変更を適用して、列をヌル不可に変更し、デフォルト値を割り当てることができます。


9

全文索引付けは、おそらくあなたの問題とは無関係です。SQL Server 2012より前ADD COLUMN NOT NULL DEFAULT ...は、更新を実行し、各行に新しく追加された列の新しいデフォルト値を入力する必要があるオフライン操作です。SQL Server 2012+では、操作がはるかに高速になります。SQLServer 11では、値の列を持つオンラインの非NULLの追加を参照してください。テーブルのメタデータのみを更新し、実際には行を更新しません。

あなたがALTER TABLE最も可能性が高い遅いため、更新のです。これは単一のトランザクションであるため、巨大なログが生成され、ログは現在成長している可能性が高く、拡張するにつれて常にゼロで消去されることに注意してください。ただし、通常の競合のために遅い場合もあります。ステートメントは、テーブルのSCH-Mロックを取得できない場合があります。sys.dm_exec_requestsこれが当てはまるかどうかを見ると、ステートメントがブロックされているか進行中かが列wait_typewait_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、ユーザー定義関数を使用してテーブル内のすべてのビットを設定しています(以下を参照)。進行中で、6800万行テーブルの100万行ごとに約1分かかります。

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デフォルトが設定されるとすぐに実行されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.