varchar(max)変数の最大サイズ


88

過去のいつでも、誰かにの最大サイズを尋ねられたら、varchar(max)2GBと言ったか、より正確な数値(2 ^ 31-1、または2147483647)を調べたでしょう。

ただし、最近のいくつかのテストで、varchar(max)変数が明らかにこのサイズを超える可能性があることがわかりました。

create table T (
    Val1 varchar(max) not null
)
go
declare @KMsg varchar(max) = REPLICATE('a',1024);
declare @MMsg varchar(max) = REPLICATE(@KMsg,1024);
declare @GMsg varchar(max) = REPLICATE(@MMsg,1024);
declare @GGMMsg varchar(max) = @GMsg + @GMsg + @MMsg;
select LEN(@GGMMsg)
insert into T(Val1) select @GGMMsg
select LEN(Val1) from T

結果:

(no column name)
2148532224
(1 row(s) affected)
Msg 7119, Level 16, State 1, Line 6
Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.
The statement has been terminated.

(no column name)
(0 row(s) affected)

それで、変数が2GBの障壁を超える可能性があることがわかったとすると、変数の実際の制限は誰か知っていvarchar(max)ますか?


(上記のテストはSQL Server 2008(R2ではありません)で完了しました。他のバージョンに適用されるかどうか知りたいです)


declare @x varchar(max) = 'XX'; SELECT LEN(REPLICATE(@x,2147483647))4294967294私のために与えますが、実行に長い時間がかかります- SELECTが戻った後でも、その余分な時間が何に費やされているかわかりません。
マーティンスミス

回答:


73

私の知る限り、2008年には上限はありません。

SQL Server 2005では、質問のコードは、@GGMMsg変数への割り当てに失敗します

最大許容サイズの2,147,483,647バイトを超えてLOBを拡張しようとしています。

以下のコードは失敗します

REPLICATE:結果の長さがターゲットのラージタイプの長さ制限(2GB)を超えています。

しかし、これらの制限は静かに解除されたようです。2008年

DECLARE @y VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),92681); 

SET @y = REPLICATE(@y,92681);

SELECT LEN(@y) 

戻り値

8589767761

32ビットのデスクトップマシンでこれを実行したので、この8 GBの文字列はアドレス可能なメモリをはるかに超えています

ランニング

select internal_objects_alloc_page_count
from sys.dm_db_task_space_usage
WHERE session_id = @@spid

戻ってきた

internal_objects_alloc_page_co 
------------------------------ 
2144456    

したがって、これはすべて長さの検証なしでLOBページに格納されるだけだと思いtempdbます。ページ数の増加はすべてSET @y = REPLICATE(@y,92681);ステートメントに関連しています。への初期変数の割り当て@yLEN計算では、これは増加しませんでした。

これについて言及する理由は、ページ数が予想よりもはるかに多いためです。8KBのページを想定すると、これは16.36GBで機能します。これは明らかに必要と思われるものの2倍です。これはおそらく、既存の文字列の最後に追加するのではなく、巨大な文字列全体をコピーして最後にチャンクを追加する必要がある文字列連結操作の非効率性が原因であると推測しています。残念ながら、現時点では、この.WRITEメソッド varchar(max)変数に対してサポートされていません

添加

私はまた、連結での動作をテストしてみたnvarchar(max) + nvarchar(max)nvarchar(max) + varchar(max)。これらはどちらも2GBの制限を超えることができます。その後、この結果をテーブルに保存しようとすると失敗しますが、エラーメッセージがAttempting to grow LOB beyond maximum allowed size of 2147483647 bytes.再度表示されます。そのためのスクリプトは以下のとおりです(実行に長い時間がかかる場合があります)。

DECLARE @y1 VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),2147483647); 
SET @y1 = @y1 + @y1;
SELECT LEN(@y1), DATALENGTH(@y1)  /*4294967294, 4294967292*/


DECLARE @y2 NVARCHAR(MAX) = REPLICATE(CAST('X' AS NVARCHAR(MAX)),1073741823); 
SET @y2 = @y2 + @y2;
SELECT LEN(@y2), DATALENGTH(@y2)  /*2147483646, 4294967292*/


DECLARE @y3 NVARCHAR(MAX) = @y2 + @y1
SELECT LEN(@y3), DATALENGTH(@y3)   /*6442450940, 12884901880*/

/*This attempt fails*/
SELECT @y1 y1, @y2 y2, @y3 y3
INTO Test

1
すばらしい-したがって、ドキュメントはむしろ「不完全」であるように見える-通常のページは、おそらく変数ではなく列にのみ適用される最大の「ストレージサイズ」を参照していることに注意します。
Damien_The_Unbeliever '30 / 09/30

@Damien-間違いなくそのように見えます。総ページ数に関して到達できる他の制限があるかどうかはわかりませんが、これはBツリー構造(SQL Server 2008内部のp.381に基づく)に格納されているので、原則として確実に拡張できます。
マーティン・スミス

@Damien_The_Unbeliever- ここでの実験に基づいて、ここのドキュメントは完全に間違っているように見え、「大きなオブジェクト(LOB)データ型の変数とパラメーター...型は最大2 GBになる可能性がある」
Martin Smith

ちょっと役に立たないが面白い。理論的には、1つの変数でディスクを埋めることができます... :-)
gbn

変数に値を格納することは、列に格納することと同じではないため、ここで少し迷っています。代わりに列でこれを試してみたいと思いますか、それとも更新がありますか?SQL Server 2000でもvarchar、変数またはvarchar列に配置しない限り、コード内のリテラル文字列に8000文字を超える値を含めることができます。
ErikE 2013

9

編集:さらに調査した後、これがdeclare @var datatype = value構文の異常(バグ?)であるという私の元の仮定は正しくありません。

その構文がサポートされていないため、スクリプトを2005年に変更し、2008年に変更したバージョンを試しました。2005年に、Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.エラーメッセージが表示されました。2008年、変更されたスクリプトはまだ成功しています。

declare @KMsg varchar(max); set @KMsg = REPLICATE('a',1024);
declare @MMsg varchar(max); set @MMsg = REPLICATE(@KMsg,1024);
declare @GMsg varchar(max); set @GMsg = REPLICATE(@MMsg,1024);
declare @GGMMsg varchar(max); set @GGMMsg = @GMsg + @GMsg + @MMsg;
select LEN(@GGMMsg)

スクリプトは常にエラーを生成しますが(テーブルの挿入を試行することにより)、2008では、最初の結果セットで常に1つの結果を取得します。これは、変数が存在し、長さが2 ^ 31-1より長いことを示します。
Damien_The_Unbeliever '30 / 09/30

@Damien_The_Unbeliever:スクリプトを変数部分だけに切り詰め、同じ結果が得られるようになりました。2005年に、私Attempting to grow...set @GGMMsg=...声明でエラーを受け取ります。2008年に、スクリプトは成功しました。
Joe Stefanelli、2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.