これは単に不可能です。 内部を参照してください。ストレージエンジン:レコードの構造
あなたのテーブルがこのようなものだと仮定します。
CREATE TABLE T1(
col_1 varchar(8000) NULL,
col_2 varchar(8000) NULL,
/*....*/
col_999 varchar(8000) NULL,
col_1000 varchar(8000) NULL
)
次に、すべての NULL
を含む行も 値は次のストレージを使用します。
- 1バイトのステータスビットA
- 1バイトのステータスビットB
- 2バイトの列カウントオフセット
- 125バイト
NULL_BITMAP
(1ビットコード> 1列あたり1,000列)
つまり、これは129バイトがすでに使用されていることが保証されています(7,931を残しています)。
いずれかの列の値がNULL
でもない場合 または空の文字列の場合は、スペースも必要です
- 2バイトの可変長列数(7,929を残す)。
- 列オフセット配列の場合は2〜2000バイト。
- データ自体。
列オフセット配列は、可変長列ごとに2バイトを消費します例外 その列とそれ以降のすべての列の長さもゼロの場合。したがって、 col_1000
を更新します col_1
を更新するときに、2000バイト全体が強制的に使用されます。 2バイトを使用するだけです。
したがって、各列に5バイトのデータを入力し、列オフセット配列の各2バイトを考慮すると、残りの7,929バイト以内の7,000バイトになります。
ただし、保存しているデータは102バイトです(51 nvarchar
文字)なので、行に残っている実際のデータへの24バイトポインタを使用して行外に格納できます。
FLOOR(7929/(24 + 2)) = 304
したがって、最良のケースは、この長さのデータの304列を格納できることです。つまり、 col_1
から更新する場合です。 、 col_2
、 ...コード> 。
col_1000
の場合 データが含まれている場合、計算は
FLOOR(5929/24) = 247
NTEXT
の場合 計算は、16バイトのポインターを使用できる
ことを除いて同様です。 これにより、データをいくつかの追加の列に圧縮できます
FLOOR(7929/(16 + 2)) = 440
SELECT
については、これらすべての行外ポインタに従う必要があります テーブルに対しては、パフォーマンスに非常に悪影響を与える可能性があります。
これをテストするためのスクリプト
DROP TABLE T1
/* Create table with 1000 columns*/
DECLARE @CreateTableScript nvarchar(max) = 'CREATE TABLE T1('
SELECT @CreateTableScript += 'col_' + LTRIM(number) + ' VARCHAR(8000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 1000
ORDER BY number
SELECT @CreateTableScript += ')'
EXEC(@CreateTableScript)
/* Insert single row with all NULL*/
INSERT INTO T1 DEFAULT VALUES
/*Updating first 304 cols succeed. Change to 305 and it fails*/
DECLARE @UpdateTableScript nvarchar(max) = 'UPDATE T1 SET '
SELECT @UpdateTableScript += 'col_' + LTRIM(number) + ' = REPLICATE(1,1000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 304
ORDER BY number
SET @UpdateTableScript = LEFT(@UpdateTableScript,LEN(@UpdateTableScript)-1)
EXEC(@UpdateTableScript)