web-dev-qa-db-ja.com

このALTER TABLEステートメントにはどのくらいの時間がかかりますか?

_Alter TABLE [XXX] Alter column [YYY] [varchar](max) NULL
_

と思います

  • 45 GBのデータ領域と2 GBのインデックス領域があります。
  • このテーブルには約300万行あります。
  • 列YYYはvarchar(8000)になり、更新できます(書き込み可能)。
  • テーブルには他に約30列あります。
  • このマシンには、他のデータベースとテーブルから約3000Gのデータがあります。

その他の情報:

  • 行の99.99%は、このvarchar(8000)NULLがあります。
  • webアプリケーションはこのテーブルに1分あたり5回ヒットする可能性があります。
  • ハードウェアはエンタープライズレベル(8コアCPUおよび256GB RAM)です。
  • このマシンには他のテーブルとデータベースがあり、約3000GBのデータがあります。

関連する_@@VERSION_の詳細:

Microsoft SQL Server 2014-12.0.4422.0(X64)
Enterpriseエディション(64ビット)

2
xingbin

この操作がシステムにかかる時間は、だれも確実または正確にはわかりません。ただし、この変更による影響は、あなたが思っているよりも少ないと思われます。 int-> bigintvarchar(8000)-> varchar(max)からのテーブルの変更を比較する簡単なテストを設定しました。最初に、2つの単純なテーブル:

CREATE TABLE dbo.t0(a int primary key, b int);
GO
CREATE TABLE dbo.t1(a int primary key, b varchar(8000));
GO

ここで、少なくとも1つの非NULL値を挿入してから、500万行以上を挿入します(私のシステムではYMMV)。

INSERT dbo.t0 VALUES(0,1);
INSERT dbo.t0 SELECT rn, NULL FROM 
( SELECT rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
  FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
) AS x;
GO -- 5,299,204 rows for me

INSERT dbo.t1 VALUES(0,'what');
INSERT dbo.t1 SELECT rn, NULL FROM 
( SELECT rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
  FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
) AS x;
GO -- 5,299,204 rows for me

次に、統計I/Oを有効にしてALTERの変更をテストしました。

SET STATISTICS IO ON;
GO
ALTER TABLE dbo.t0 ALTER COLUMN b bigint NULL; 
GO -- 9 seconds, 122,506 reads
SET STATISTICS IO OFF;

これは9秒で終了し、122,506回の読み取りが必要でした。

SET STATISTICS IO ON;
GO
ALTER TABLE dbo.t1 ALTER COLUMN b varchar(max) NULL; 
GO -- 5 seconds, 8,562 logical reads
SET STATISTICS IO OFF;

これは5秒で終了し、8,562リードのみが必要でした。

したがって、どちらの操作もオンラインでは発生せず、実際の結果はハードウェアやテーブルの構造によって異なる場合がありますが、これはWindowsが低かった場合VMであるため、これより良い。

また、null許容列にデータを追加してテストしました。テーブルを削除し、上記のスクリプトを使用して再作成および再設定した後、これを実行してsomethingを100,000行に配置します。

;WITH x AS (SELECT TOP (100000) a,b FROM dbo.t1 ORDER BY NEWID())
UPDATE x SET b = a;
GO
;WITH x AS (SELECT TOP (100000) a,b FROM dbo.t1 ORDER BY NEWID())
UPDATE x SET b = REPLICATE(RTRIM(a), 1000);
GO

これには、後続のALTERs(3分以上)よりもway時間がかかりました。最初のALTERはまだ9秒かかりましたが、単純に読み取りの数が(189,854に)増加したため、2番目の_は17秒かかりました。これは、たとえば、このテーブルに30個の他の列がある場合に起こることと似ています。ここで実際に何が起こっているのかについては、17秒はかなり良いと私はまだ思っています。これも、エンタープライズレベルの環境とはかけ離れています。

Paulが指摘しているように、SQL Server 2016以降では、これをオンラインで実行できますが、制限と制限があります。詳細については ドキュメントを参照

ALTER TABLE dbo.t1 ALTER COLUMN b varchar(max) NULL WITH (ONLINE = ON);

ただし、このオプションはSQL Server 2014では使用できません。

これをよりオンラインで実行する方法の1つは、その列を別の関連するテーブルに移動することです。カットオーバーの方法にはいくつかの複雑な点があり、コードの束に影響を与える可能性がありますが、ビューを使用してほとんどの問題を(少なくとも一時的に)解決できます。

7
Aaron Bertrand

SQL Server 2016より前のバージョンでは最大900バイトまでしかインデックス付けできないため、VARCHAR(8000)列にはインデックスが付けられないため、インデックスについて心配する必要はありません。

その変更を行うときに、誰が何にテーブルにアクセスするかを検討する必要があります。 SQL Serverに関する限り、このような変更はデータ型の変更と見なされるため、メタデータの変更と見なされるVARCHARサイズの変更よりも時間がかかります。

内部で起こっていることは、VARCHAR(8000)列のデータが行の外にシフトされ、レコードにVARCHAR(MAX)で表されるデータへのポインターが含まれるようになることです。

実行時間は、次のような多くのものに依存します

  • ハードウェア-ストレージパフォーマンス、RAM
  • 使用率-ボックスで他にどのようなプロセスが行われているか。
  • TempDBのサイズ
  • 300万レコードのうち、VARCHAR(8000)フィールドに何かあるレコードの数
  • VARCHAR(8000)フィールドに実際にあるバイト数。ほとんどのレコードに大きな文字列がある場合、これには長い時間がかかります。

個人的には、テスト環境内でリハーサルを行い、営業時間外の静かな時間に行うことを期待しています。

4
Dave Poole