varchar (255) veya varchar (256)?


21

Ben kullanmalı mıyım varchar(255)ya varchar(256)tabloları tasarlarken? Bir baytın sütun uzunluğu veya meta veri depolamak için kullanıldığını duydum.

Artık bu noktada önemli mi?

İnternette bazı yayınlar gördüm, ancak Oracle ve MySQL için geçerli.

Microsoft SQL Server 2016 Enterprise Edition'ımız var, bu ortam için nasıl geçerlidir?

Şimdi, örneğin, müşterilerime örneğin 256 yerine 255 karakterlik bir metin açıklaması saklamamı söylersem, herhangi bir fark var mı? Ne okudum "Maksimum 255 karakter uzunluğunda, DBMS alandaki verilerin uzunluğunu belirtmek için tek bir bayt kullanmayı seçebilir. Sınır 256 veya daha büyük olsaydı, iki bayt gerekli olurdu." Bu doğru mu?


Bilginize: Bu soru MSDN forumlarında çapraz olarak yayınlanmıştır: social.msdn.microsoft.com/Forums/sqlserver/en-US/…
Solomon Rutzky

Yanıtlar:


36

Boyut her sütunu uygun. Her sütun için "standart" bir boyut KULLANMAYIN. Yalnızca 30 karaktere ihtiyacınız varsa, neden 255'i işleyebilecek bir sütun oluşturmalısınız? varchar(max)Dize sütunlarınız için kullanmak istemediğiniz için çok mutluyum .

Bir sütunu dizine eklemeniz gerekiyorsa veya bir sütunu birincil anahtar olarak kullanıyorsanız ve bunun yabancı anahtar başvuruları varsa, bu özellikle ihtiyatlı bir tavsiyedir. SQL Server, sorgu işleme için tahmini bellek gereksinimlerini anlamak için sorgu iyileştiricisindeki her sütunun boyutunu kullanır. Büyük boyutlu sütunlara sahip olmak performansa zarar verebilir.

Büyük boyutlu sütunlardaki dizinler, hataların oluşmasına neden olabilir:

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);

Yukarıdaki dizini yaratma girişimi şu uyarıyla sonuçlanır:

Uyarı! Maksimum anahtar uzunluğu 900 bayttır. 'IX_WideIndex_01' dizininin uzunluğu maksimum 1110 bayttır. Büyük değerlerin bazı birleşimleri için ekleme / güncelleme işlemi başarısız olur.

900 bayt, kümelenmiş dizinler (ve SQL Server 2012 ve daha eski sürümlerde kümelenmemiş dizinler) için maksimum anahtar boyutudur. 1700 bayt, SQL Server'ın yeni sürümlerindeki kümelenmemiş dizinler için maksimum anahtar boyutudur. (255) gibi genel genişliğe sahip sütunlar tasarlarsanız, bu uyarıya beklenenden daha sık rastlayabilirsiniz.

Depolama içleriyle ilgileniyorsanız, SQL Server'ın sıkıştırılmamış satır depolama verilerini nasıl depoladığını daha iyi anlamak için aşağıdaki küçük testi kullanabilirsiniz.

İlk olarak, çeşitli boyutlardaki sütunları depolayabileceğimiz bir tablo oluşturacağız:

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
);

Şimdi tek bir satır ekleyeceğiz:

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

Bu sorgu, belgesiz ve desteklenmeyen işlevlerini kullanır sys.fn_RowDumpCrackerve sys.fn_PhyslocCrackertablo hakkında bazı ilginç ayrıntıları göstermek için:

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

Çıktı buna benzer olacaktır:

╔═════════════════════╦════════════╦═════════╦════ ══════╦══════════════════════════╦══════════╦═════ ════════╦═════════════╦═════════╦═════════╦═══════ ══╗
║ partition_id ║ colName ║ IsInrow ║ IsSparse ║ IsRecordPrefixCompressed ║ IsSymbol ║ PrefixBytes ║ InRowLength ║ dosya_kimliği ║ sayfa_kimliği ║ slot_id ║
╠═════════════════════╬════════════╬═════════╬════ ══════╬══════════════════════════╬══════════╬═════ ════════╬═════════════╬═════════╬═════════╬═══════ ══╣
║ 1729382263096344576 ║ varchar30 ║ 1 ║ 0 ║ 0 ║ 0 ║ 0 ║ 30 ║ 1 ║ 1912 ║ 0 ║
║ 1729382263096344576 ║ varchar255 ║ 1 ║ 0 ║ 0 ║ 0 ║ 0 ║ 255 ║ 1 ║ 1912 ║ 0 ║
║ 1729382263096344576 ║ varchar256 ║ 1 ║ 0 ║ 0 ║ 0 ║ 0 ║ 256 ║ 1 ║ 1912 ║ 0 ║
╚═════════════════════╩════════════╩═════════╩════ ══════╩══════════════════════════╩══════════╩═════ ════════╩═════════════╩═════════╩═════════╩═══════ ══╝

Gördüğünüz gibi InRowLength, her bir satırın fiziksel değeri, "dosya_kimliği", "sayfa_kimliği" ve "yuva_kimliği" ile birlikte gösterilir.

Yukarıdaki sorgu sonuçlarından file_idve page_iddeğerlerini alıp DBCC PAGEonlarla birlikte çalışırsak , gerçek fiziksel sayfa içeriğini görebiliriz:

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

Makinemden elde edilen sonuçlar:

SAYFA: (1: 1912)


TAMPON:


BUF @ 0x00000000FF5B2E80

bpage = 0x0000000024130000 bhash = 0x0000000000000000 bpageno = (1: 1912)
bdbid = 2 ırk = 0 bcputicks = 0
bsampleCount = 0 bKullanım1 = 32497 bstat = 0x10b
blog = 0x212121cc bnext = 0x0000000000000000          

SAYFA BAŞLIĞI:


Sayfa @ 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
Meta veriler: AllocUnitId = 2233785421652951040                              
Meta veriler: PartitionId = 1945555045333008384 Meta veriler: IndexId = 0
Meta veriler: 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 Parça Kimliği = 1                      

Tahsis Durumu

GAM (1: 2) = TAHSİSLİ SGAM (1: 3) = TAHSİS EDİLMEYEN PFS DEĞİL (1: 1) = 0x41 TAHSİSLİ 50_PCT_FULL
DIFF (1: 6) = DEĞİŞTİRİLMEDİ ML (1: 7) = MIN_LOGGED DEĞİL           

Yuva 0 Ofset 0x60 Uzunluk 556

Kayıt Türü = PRIMARY_RECORD Kayıt Özellikleri = NULL_BITMAP VARIABLE_COLUMNS
Kayıt Boyutu = 556                   
Bellek Dökümü @ 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 3333333333333333333333
0000000000000140: 33333333 33333333 33333333 33333333 33333333 33333333333333333333
0000000000000154: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
0000000000000168: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
000000000000017C: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
0000000000000190: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
00000000000001A4: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
00000000000001B8: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
00000000000001CC: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
00000000000001E0: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
00000000000001F4: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
0000000000000208: 33333333 33333333 33333333 33333333 33333333 3333333333333333333333
000000000000021C: 33333333 33333333 33333333 33333333 3333333333333333

Yuva 0 Sütun 1 Ofset 0xf Uzunluk 30 Uzunluk (fiziksel) 30

varchar30 = 111111111111111111111111111111                               

Yuva 0 Sütun 2 Ofset 0x2d Uzunluk 255 Uzunluk (fiziksel) 255

varchar255 = 222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
222222222222222222222222222222222222222222                               

Yuva 0 Sütun 3 Ofset 0x12c Uzunluk 256 Uzunluk (fiziksel) 256

varchar256 = 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
3333333333333333333333333333333333333333333                              

16

Diğerleri, uzunluğu saklamak için gereken bayt sayısının sabit olduğunu zaten belirtti. Sorunuzda bu bölüme odaklanmak istedim:

Artık bu noktada önemli mi?

Kurumsal baskı ile etiketlenmiş sorunuz var, bu da genellikle makul miktarda veriye sahip olacağınız anlamına gelir. Genellikle satır başına bir bayt arasındaki farklar pratikte çok fazla önemli değildir. Örneğin, tam dolu bir VARCHAR(255)sütuna sahip aşağıdaki tablo diskte 143176 KB yer kaplar:

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';

Sonuçlar:

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

Tamamen dolu bir VARCHAR(256)sütuna sahip ikinci bir tablo oluşturalım . Bu satır başına en az bir bayt daha alacak, değil mi?

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';

Sonuçlar:

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

Her iki tablo da aynı miktarda yer kaplar. Her 8k sayfaya aynı sayıda satır sığar. Uygulamanızı optimize etmek için zaman harcamanız harika, ancak farklı alanlara odaklanmaktan daha iyi olduğunuzdan şüpheleniyorum.


7

Varchar'ın beyan edilen boyutunun performans etkisi yoktur. Veriler aslında sayfa sıkıştırması veya satır sıkıştırması olan bir satır deposu olarak saklanabilir. Kümelenmiş bir Sütun Deposu veya Bellek için Optimize Edilmiş bir tablo olarak Bunların her biri farklı performans değiş tokuşlarına sahip olacaktır, ancak varchar (255) veya varchar (256) bildirmeniz önemli değildir.


9
@ DavidBrowne-Microsoft hayır, "varchar bildirilen boyutu hiçbir performans etkisi vardır" kesinlikle doğru değildir - veri türü boyutu sorgular için bellek hibeleri etkiler. Daha fazla bilgi için brentozar.com/archive/2017/02/memory-grants-data-size adresini ziyaret edin.
Brent Ozar

6
Basit tutmaya ve erken optimizasyondan vazgeçmeye çalışıyorum.
David Browne - Microsoft
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.