web-dev-qa-db-ja.com

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

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

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

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

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

  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にアップグレードされます)。

14
BobbyR-1of4

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

16

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

アップデートが原因でALTER TABLEが遅くなっている可能性があります。これは単一のトランザクションであるため、巨大なログが生成され、ログは現在増加している可能性が高く、拡張するにつれて常にゼロになっています。ただし、通常の競合のために遅くなる可能性もあります。ステートメントがテーブルのSCH-Mロックを取得できない場合があります。 sys.dm_exec_requests を見ると、これが当てはまるかどうかがわかります。wait_type列とwait_resource列は、 ALTERステートメントがブロックされているか、進行中です。

9
Remus Rusanu

回答者が最初に質問に追加した回答:

ジェイソンの答え に従って、代わりに次の更新を発行しました:

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ビットを設定しています(以下を参照)。これは進行中であり、約6,800万行のテーブルの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

それが完了したら、最終的なスキーマ調整を実行して、新しいビット列をnull以外にする予定です。

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

うまくいけば、この最後のスキーマ更新は、すべての値がnullでなく、NumericValueのデフォルトが設定されるとすぐに実行されます。

0
user126897