Gdyby kiedykolwiek w przeszłości ktoś zapytał mnie o maksymalny rozmiar a varchar(max)
, powiedziałbym 2 GB lub szukał dokładniejszej liczby (2 ^ 31-1 lub 2147483647).
Jednak w niektórych niedawnych testach odkryłem, że varchar(max)
zmienne mogą najwyraźniej przekraczać ten rozmiar:
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
Wyniki:
(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)
Biorąc więc pod uwagę, że teraz wiem, że zmienna może przekroczyć barierę 2 GB - czy ktoś wie, jaki jest faktyczny limit dla varchar(max)
zmiennej?
(Powyższy test został ukończony na SQL Server 2008 (nie R2). Chciałbym wiedzieć, czy dotyczy to innych wersji)
sql-server
tsql
Damien_The_Unbeliever
źródło
źródło
declare @x varchar(max) = 'XX'; SELECT LEN(REPLICATE(@x,2147483647))
daje4294967294
mi, ale bieganie zajmuje dużo czasu - nawet poSELECT
powrocie, więc nie jestem pewien, na co ten dodatkowy czas spędza.Odpowiedzi:
O ile wiem, w 2008 roku nie ma górnej granicy.
W SQL Server 2005 kod w twoim pytaniu nie powiedzie się przy przypisaniu do
@GGMMsg
zmiennej zponiższy kod nie działa
Jednak wydaje się, że ograniczenia te zostały po cichu zniesione. W 2008r
DECLARE @y VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),92681); SET @y = REPLICATE(@y,92681); SELECT LEN(@y)
Zwroty
Uruchomiłem to na moim 32-bitowym komputerze stacjonarnym, więc ten ciąg 8 GB jest znacznie większy niż pamięć adresowalna
Bieganie
select internal_objects_alloc_page_count from sys.dm_db_task_space_usage WHERE session_id = @@spid
Zwrócony
internal_objects_alloc_page_co ------------------------------ 2144456
więc zakładam, że to wszystko jest po prostu zapisywane na
LOB
stronachtempdb
bez sprawdzania długości. Wzrost liczby stron był związany zeSET @y = REPLICATE(@y,92681);
stwierdzeniem. Początkowe przypisanie zmiennej do@y
iLEN
obliczenia nie zwiększyły tego.Powodem, dla którego o tym wspominam, jest to, że liczba stron jest znacznie większa, niż się spodziewałem. Zakładając, że strona ma 8 KB, wychodzi to na 16,36 GB, co jest oczywiście mniej więcej dwa razy większe niż wydaje się konieczne. Spekuluję, że jest to prawdopodobnie spowodowane nieefektywnością operacji łączenia ciągów, która wymaga skopiowania całego ogromnego ciągu i dołączenia fragmentu na końcu zamiast możliwości dodania go na końcu istniejącego ciągu. Niestety w tej chwili
.WRITE
metoda nie jest obsługiwana dla zmiennych varchar (max).Dodanie
Przetestowałem również zachowanie z łączeniem
nvarchar(max) + nvarchar(max)
invarchar(max) + varchar(max)
. Oba pozwalają na przekroczenie limitu 2 GB. Próba zapisania wyników w tabeli kończy się jednak niepowodzeniem iAttempting to grow LOB beyond maximum allowed size of 2147483647 bytes.
ponownie pojawia się komunikat o błędzie . Skrypt do tego znajduje się poniżej (może zająć dużo czasu).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
źródło
varchar
wartości dłuższe niż 8000 znaków w literałowych ciągach znaków w kodzie, o ile nie próbowałeś umieszczać ich w zmiennej lubvarchar
kolumnie.EDYCJA : Po dalszych badaniach moje pierwotne założenie, że była to anomalia (błąd?) W
declare @var datatype = value
składni, jest niepoprawne.Zmodyfikowałem twój skrypt na rok 2005, ponieważ ta składnia nie jest obsługiwana, a następnie wypróbowałem zmodyfikowaną wersję w roku 2008. W 2005 pojawia się
Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.
komunikat o błędzie. W 2008 roku zmodyfikowany skrypt nadal odnosi sukcesy.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)
źródło
Attempting to grow...
błąd wset @GGMMsg=...
wyciągu. W 2008 roku scenariusz się udał.