DataValue
列にフルテキストインデックスが作成されている大きな(6700万行)名前値テーブルがあります。
次のコマンドを実行しようとすると、
ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;
1時間10分実行されますが、約6,700万行を含むVisitorData
テーブルではまだ完了しません。
以下は、テーブルに関する詳細です。
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にアップグレードされます)。
変更中に列にデフォルト値を割り当て、それをnull不可の列で強制するため、スキーマの変更に非常に時間がかかり、6000万行以上の列に列を設定する必要があります。これは非常にコストのかかる操作です。アプリケーションの要件が何であるかはわかりませんが、スキーマの変更を高速化するアプローチは、デフォルト値のないnull許容列として追加し、更新をバッチで実行して、列の値として0を割り当てることです。更新が完了したら、別のスキーマ変更を適用して、列をnull不可に変更し、デフォルト値を割り当てることができます。
フルテキストインデックスは、おそらく問題とは無関係です。 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
ステートメントがブロックされているか、進行中です。
回答者が最初に質問に追加した回答:
ジェイソンの答え に従って、代わりに次の更新を発行しました:
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
のデフォルトが設定されるとすぐに実行されます。