varchar(255)またはvarchar(256)?


21

テーブルを使用する必要がありますvarchar(255)varchar(256)?列の長さ、またはメタデータの保存に1バイトが使用されていると聞きました。

この時点でそれはもう重要ですか?

私はインターネット上でいくつかの投稿を見ましたが、それらはOracleとMySQLに適用されます。

Microsoft SQL Server 2016 Enterprise Editionがありますが、この環境にどのように適用されますか?

ここで、たとえば、テキストの説明を256ではなく255文字に保つようにクライアントに指示した場合、違いはありますか?私が読んだこと「DBMSは255文字の最大長で、フィールド内のデータの長さを示すために単一バイトを使用することを選択できます。制限が256以上の場合、2バイトが必要になります。」これは本当ですか?


FYI:この質問MSDNフォーラムにクロス投稿されました:social.msdn.microsoft.com/Forums/sqlserver/en-US/...
ソロモンRutzky

回答:


36

列を適切にサイズ設定します。各列に「標準」サイズを使用しないでください。30文字しか必要ない場合、なぜ255を処理できる列を作成するのですか?varchar(max)文字列列に使用することを推奨していないのはとてもうれしいです。

これは、列にインデックスを作成する必要がある場合、または列を主キーとして使用しており、外部キー参照がある場合に特に賢明なアドバイスです。SQL Serverは、クエリオプティマイザーの各列のサイズを使用して、クエリ処理の推定メモリ要件を理解します。列のサイズが大きすぎると、パフォーマンスが低下する可能性があります。

サイズが大きい列のインデックスは、エラーが生成される可能性があります。

CREATE TABLE dbo.WideIndex
(
    col1 varchar(255) NOT NULL
    , col2 varchar(255) NOT NULL
    , col3 varchar(600) NOT NULL    
);

CREATE INDEX IX_WideIndex_01
ON dbo.WideIndex (col1, col2, col3);

上記のインデックスを作成しようとすると、次の警告が表示されます。

警告!キーの最大長は900バイトです。インデックス「IX_WideIndex_01」の最大長は1110バイトです。大きな値のいくつかの組み合わせでは、挿入/更新操作は失敗します。

900バイトは、クラスター化インデックス(およびSQL Server 2012以前の非クラスター化インデックス)の最大キーサイズです。SQL Serverの新しいバージョンの非クラスター化インデックスの最大キーサイズは1700バイトです。(255)などの一般的な幅の列を設計する場合、この警告が予想よりもはるかに多く発生する可能性があります。

ストレージ内部に興味がある場合は、次の小さなテストを使用して、SQL Serverが非圧縮行ストアデータを格納する方法をよりよく理解できます。

最初に、さまざまなサイズの列を格納できるテーブルを作成します。

IF OBJECT_ID(N'dbo.varchartest', N'U') IS NOT NULL
DROP TABLE dbo.varchartest;
GO

CREATE TABLE dbo.varchartest
(
    varchar30 varchar(30) NOT NULL
    , varchar255 varchar(255) NOT NULL
    , varchar256 varchar(256) NOT NULL
);

次に、単一の行を挿入します。

INSERT INTO dbo.varchartest (varchar30, varchar255, varchar256)
VALUES (REPLICATE('1', 30), REPLICATE('2', 255), REPLICATE('3', 256));

このクエリは、ドキュメント化されていない、サポートされていない関数sys.fn_RowDumpCrackerを使用sys.fn_PhyslocCrackerして、テーブルに関する興味深い詳細を表示します。

SELECT rdc.*
    , plc.*
FROM dbo.varchartest vct
CROSS APPLY  sys.fn_RowDumpCracker(%%rowdump%%) rdc
CROSS APPLY sys.fn_physlocCracker(%%physloc%%) plc

出力は次のようになります。

╔=============================================== ======╦=============================================== ========╦=============╦=================╦======= ==╗
║partition_id col colName║IsInrow║IsSparse║IsRecordPrefixCompressed║IsSymbol║PrefixBytes║InRowLength║file_id║page_id║slot_id║
╠=============================================== ======╬=============================================== ========╬===============================╬======= ==╣
║1729382263096344576 var varchar30║1║0║0║0║0║30║1║1912║0║
║1729382263096344576║varchar255║1║0║0║0║0║255║1║1912║0║
║1729382263096344576 var varchar256║1║0║0║0║0║256║1║1912║0║
╚=============================================== ======╩=============================================== ========╩===============================╩======= ==╝

ご覧のとおりInRowLength、各行の物理ストレージの場所( "file_id"、 "page_id"、および "slot_id")とともに各値が表示されます。

上記のクエリ結果からfile_idand page_id値を取得して実行するDBCC PAGEと、実際の物理ページのコンテンツを確認できます。

DBCC TRACEON (3604); --send display to the client
DBCC PAGE (tempdb, 1, 1912, 3); --database, file_id, page_id, 3 to show page contents
DBCC TRACEOFF (3604);--reset display back to the error log

私のマシンの結果は次のとおりです。

ページ:(1:1912)


バッファ:


BUF @ 0x00000000FF5B2E80

bpage = 0x0000000024130000 bhash = 0x0000000000000000 bpageno =(1:1912)
bdbid = 2 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 32497 bstat = 0x10b
ブログ= 0x212121cc bnext = 0x0000000000000000          

ページヘッダー:


ページ@ 0x0000000024130000

m_pageId =(1:1912)m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8000
m_objId(AllocUnitId.idObj)= 98834 m_indexId(AllocUnitId.idInd)= 7936
メタデータ:AllocUnitId = 2233785421652951040                              
メタデータ:PartitionId = 1945555045333008384メタデータ:IndexId = 0
メタデータ:ObjectId = 34099162 m_prevPage =(0:0)m_nextPage =(0:0)
pminlen = 4 m_slotCnt = 1 m_freeCnt = 7538
m_freeData = 652 m_reservedCnt = 0 m_lsn =(35:210971:362)
m_xactReserved = 0 m_xdesId =(0:0)m_ghostRecCnt = 0
m_tornBits = 0 DB Frag ID = 1                      

割り当てステータス

GAM(1:2)= ALLOCATED SGAM(1:3)= NOT ALLOCATED PFS(1:1)= 0x41 ALLOCATED 50_PCT_FULL
DIFF(1:6)=変更なしML(1:7)= NOT MIN_LOGGED           

スロット0オフセット0x60長さ556

レコードタイプ= PRIMARY_RECORDレコード属性= NULL_BITMAP VARIABLE_COLUMNS
レコードサイズ= 556                   
メモリダンプ@ 0x000000005145A060

0000000000000000:30000400 03000003 002d002c 012c0231 31313131 0 ........-。、。、。11111
0000000000000014:31313131 31313131 31313131 31313131 31313131 11111111111111111111
0000000000000028:31313131 31323232 32323232 32323232 32323232 11111222222222222222
000000000000003C:32323232 32323232 32323232 32323232 32323232 22222222222222222222
0000000000000050:32323232 32323232 32323232 32323232 32323232 22222222222222222222
0000000000000064:32323232 32323232 32323232 32323232 32323232 22222222222222222222
0000000000000078:32323232 32323232 32323232 32323232 32323232 22222222222222222222
000000000000008C:32323232 32323232 32323232 32323232 32323232 22222222222222222222
00000000000000A0:32323232 32323232 32323232 32323232 32323232 22222222222222222222
00000000000000B4:32323232 32323232 32323232 32323232 32323232 22222222222222222222
00000000000000C8:32323232 32323232 32323232 32323232 32323232 22222222222222222222
00000000000000DC:32323232 32323232 32323232 32323232 32323232 22222222222222222222
00000000000000F0:32323232 32323232 32323232 32323232 32323232 22222222222222222222
0000000000000104:32323232 32323232 32323232 32323232 32323232 22222222222222222222
0000000000000118:32323232 32323232 32323232 32323232 32323232 22222222222222222222
000000000000012C:33333333 33333333 33333333 33333333 33333333 33333333333333333333333333333
0000000000000140:33333333 33333333 33333333 33333333 33333333 33333333333333333333 33333333
0000000000000154:33333333 33333333 33333333 33333333 33333333 33333333333333333333 33333333
0000000000000168:33333333 33333333 33333333 33333333 33333333 33333333333333333333 33333333
000000000000017C:33333333 33333333 33333333 33333333 33333333 33333333333333333333333333333
0000000000000190:33333333 33333333 33333333 33333333 33333333 33333333333333333333 33333333 33333333
00000000000001A4:33333333 33333333 33333333 33333333 33333333 33333333333333333333333
00000000000001B8:33333333 33333333 33333333 33333333 33333333 33333333333333333333333333333
00000000000001CC:33333333 33333333 33333333 33333333 33333333 33333333333333333333333333333
00000000000001E0:33333333 33333333 33333333 33333333 33333333 33333333333333333333333
00000000000001F4:33333333 33333333 33333333 33333333 33333333 33333333333333333333333333333
0000000000000208:33333333 33333333 33333333 33333333 33333333 33333333333333333333 33333333
000000000000021C:33333333 33333333 33333333 33333333 3333333333333333

スロット0列1オフセット0xf長さ30長さ(物理)30

varchar30 = 111111111111111111111111111111111                               

スロット0列2オフセット0x2d長さ255長さ(物理)255

varchar255 = 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
222222222222222222222222222222222222222222222                               

スロット0列3オフセット0x12c長さ256長さ(物理)256

varchar256 = 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
3333333333333333333333333333333333333333333333                              

16

他の人は、長さを保存するのに必要なバイト数が固定されていることをすでに指摘しています。あなたの質問のこの部分に焦点を当てたいと思いました:

この時点でそれはもう重要ですか?

エンタープライズエディションでタグ付けされた質問があります。これは通常、かなりの量のデータがあることを意味します。多くの場合、行ごとに1バイトの違いは実際にはあまり重要ではありません。たとえば、VARCHAR(255)列が完全に埋められた次の表は、ディスク上の143176 KBのスペースを占有します。

DROP TABLE IF EXISTS dbo.V255_FULL;

CREATE TABLE dbo.V255_FULL (
    ID1 BIGINT NOT NULL,
    ID2 BIGINT NOT NULL,
    V255 VARCHAR(255)
);

INSERT INTO dbo.V255_FULL WITH (TABLOCK)
SELECT TOP (500000) 0, 0, REPLICATE('A', 255)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

EXEC sp_spaceused 'V255_FULL';

結果:

╔═══════════╦══════════════════════╦═══════════╦═══════════╦════════════╦════════╗
   name             rows          reserved     data     index_size  unused 
╠═══════════╬══════════════════════╬═══════════╬═══════════╬════════════╬════════╣
 V255_FULL  500000                143176 KB  142888 KB  8 KB        280 KB 
╚═══════════╩══════════════════════╩═══════════╩═══════════╩════════════╩════════╝

VARCHAR(256)列がいっぱいになった2番目のテーブルを作成しましょう。行ごとに少なくとももう1バイト必要ですよね?

DROP TABLE IF EXISTS dbo.V256_FULL;

CREATE TABLE dbo.V256_FULL (
    ID1 BIGINT NOT NULL,
    ID2 BIGINT NOT NULL,
    V256 VARCHAR(256)
);

INSERT INTO dbo.V256_FULL WITH (TABLOCK)
SELECT TOP (500000) 0, 0, REPLICATE('A', 256)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

EXEC sp_spaceused 'V256_FULL';

結果:

╔═══════════╦══════════════════════╦═══════════╦═══════════╦════════════╦════════╗
   name             rows          reserved     data     index_size  unused 
╠═══════════╬══════════════════════╬═══════════╬═══════════╬════════════╬════════╣
 V256_FULL  500000                143176 KB  142888 KB  8 KB        280 KB 
╚═══════════╩══════════════════════╩═══════════╩═══════════╩════════════╩════════╝

両方のテーブルが同じ量のスペースを占有することが起こります。同じ数の行が各8kページに収まります。アプリケーションの最適化に時間を費やしたいのは素晴らしいことですが、さまざまな分野に焦点を合わせた方が良いと思います。


7

宣言されたvarcharのサイズはパフォーマンスに影響しません。データは、実際にはページ圧縮または行圧縮を備えた行ストアとして格納される場合があります。クラスター化された列ストア、またはメモリー最適化テーブルとして。これらはそれぞれパフォーマンスのトレードオフが異なりますが、varchar(255)とvarchar(256)のどちらを宣言するかは重要ではありません。


9
@ DavidBrowne-Microsoftいいえ、「宣言されたvarcharのサイズはパフォーマンスに影響を与えません」は間違いです-データ型のサイズはクエリのメモリ許可に影響します。詳細については、brentozar.com / archive / 2017/02 / memory-grants-data-sizeを参照してください。
ブレントオザー

6
シンプルに保ち、時期尚早な最適化を妨げようとします。
デビッドブラウン-マイクロソフト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.