Ограничения SQL NVARCHAR и VARCHAR
все, у меня есть большой (неизбежный) динамический SQL-запрос. Из-за количества полей в критериях выбора строка, содержащая динамический SQL, увеличивается более чем на 4000 символов. Теперь я понимаю, что существует 4000 max set для NVARCHAR(MAX)
, но глядя на выполненный SQL в Профилировщике сервера для оператора
DELARE @SQL NVARCHAR(MAX);
SET @SQL = 'SomeMassiveString > 4000 chars...';
EXEC(@SQL);
GO
кажется, работает(!?), для другого запроса, который также велик, он выдает ошибку, связанную с этим пределом 4000 (!?), он в основном обрезает все SQL после этого 4000 limit и оставляет меня с синтаксической ошибкой. Несмотря на это в профилировщике, он показывает этот динамический SQL-запрос в полное(!?).
что именно здесь происходит, и я должен просто преобразовать эту переменную @SQL в VARCHAR и продолжить с ней?
Спасибо за ваше время.
Ps. Было бы также неплохо иметь возможность распечатать более 4000 символов, чтобы посмотреть на эти большие запросы. Следующие ограничиваются 4000
SELECT CONVERT(XML, @SQL);
PRINT(@SQL);
есть ли другой хороший способ?
4 ответов
я понимаю, что существует 4000 max set для
NVARCHAR(MAX)
ваше понимание неверно. nvarchar(max)
может хранить до (и за пределами иногда) 2 ГБ данных (1 миллиард двухбайтовых символов).
с nchar и nvarchar в книгах онлайн грамматика
nvarchar [ ( n | max ) ]
на |
символ означает, что эти альтернативы. т. е. вы указываете или n
или буквальном max
.
если вы решите указать конкретный n
тогда это должно быть между 1 и 4000, но с помощью max
определяет его как тип данных большого объекта (замена для ntext
, который является устаревшим).
на самом деле в SQL Server 2008 кажется, что для переменная предел 2GB может быть превышен на неопределенный срок при условии достаточного пространства в tempdb
(показано здесь)
относительно других частей ваш вопрос!--62-->
усечение при объединении зависит от типа данных.
-
varchar(n) + varchar(n)
усечет на 8000 символов. -
nvarchar(n) + nvarchar(n)
отсекает на 4000 символов. -
varchar(n) + nvarchar(n)
отсекает на 4000 символов.nvarchar
имеет более высокий приоритет, поэтому результатnvarchar(4,000)
-
[n]varchar(max)
+[n]varchar(max)
не будет усекать (для -
varchar(max)
+varchar(n)
не будет усекать (для varchar(max). -
varchar(max)
+nvarchar(n)
не будет усекать (для nvarchar(max). -
nvarchar(max)
+varchar(n)
сначала преобразоватьvarchar(n)
вход вnvarchar(n)
а затем выполните конкатенацию. если длинаvarchar(n)
строка больше, чем 4000 символов бросок будетnvarchar(4000)
и произойдет усечение.
типы данных строковые литералы
если вы используете N
префикс и строка длиной nvarchar(n) здесь n
- длина строки. Так что N'Foo'
будет рассматриваться как nvarchar(3)
например. Если строка длиннее 4000 символов, она будет рассматриваться как nvarchar(max)
если вы не используете N
префикс и строка длиной varchar(n) здесь n
- длина строки. Если дольше varchar(max)
для обоих, если длина строки равна нулю, то n
имеет значение 1.
новые элементы синтаксиса.
1. на CONCAT
функция здесь не помогает
DECLARE @A5000 VARCHAR(5000) = REPLICATE('A',5000);
SELECT DATALENGTH(@A5000 + @A5000),
DATALENGTH(CONCAT(@A5000,@A5000));
вышеуказанное возвращает 8000 для обоих методов конкатенации.
2. будьте осторожны с +=
DECLARE @A VARCHAR(MAX) = '';
SET @A+= REPLICATE('A',5000) + REPLICATE('A',5000)
DECLARE @B VARCHAR(MAX) = '';
SET @B = @B + REPLICATE('A',5000) + REPLICATE('A',5000)
SELECT DATALENGTH(@A),
DATALENGTH(@B);`
возвращает
-------------------- --------------------
8000 10000
обратите внимание, что @A
обнаружена усечение.
как решить проблему, которую вы испытываете.
вы получаете усечение либо потому, что вы объединяете два не max
типы данных вместе или потому, что вы конкатенации varchar(4001 - 8000)
строку nvarchar
введенную строку (даже nvarchar(max)
).
чтобы избежать второй проблемы, просто убедитесь, что все строковые литералы (или, по крайней мере, те, которые имеют длину в диапазоне 4001 - 8000) предваряются N
.
в избегайте первой проблемы измените назначение с
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = 'Foo' + 'Bar' + ...;
до
DECLARE @SQL NVARCHAR(MAX) = '';
SET @SQL = @SQL + N'Foo' + N'Bar'
так что NVARCHAR(MAX)
участвует в конкатенации с самого начала (в результате каждой конкатенации также будет NVARCHAR(MAX)
она будет принята)
избегая усечения при просмотре
убедитесь, что у вас есть режим" результаты в сетку", затем вы можете использовать
select @SQL as [processing-instruction(x)] FOR XML PATH
параметры SSMS позволяют установить неограниченную длину для XML
результаты. The processing-instruction
бит позволяет избежать проблем с символы, такие как <
отображается как <
.
Итак, если позже вниз по линии проблема в том, что у вас есть запрос, который больше допустимого размера (что может произойти, если он продолжает расти), вам придется разбить его на куски и выполнить строковые значения. Итак, предположим, у вас есть хранимая процедура, подобная следующей:
CREATE PROCEDURE ExecuteMyHugeQuery
@SQL VARCHAR(MAX) -- 2GB size limit as stated by Martin Smith
AS
BEGIN
-- Now, if the length is greater than some arbitrary value
-- Let's say 2000 for this example
-- Let's chunk it
-- Let's also assume we won't allow anything larger than 8000 total
DECLARE @len INT
SELECT @len = LEN(@SQL)
IF (@len > 8000)
BEGIN
RAISERROR ('The query cannot be larger than 8000 characters total.',
16,
1);
END
-- Let's declare our possible chunks
DECLARE @Chunk1 VARCHAR(2000),
@Chunk2 VARCHAR(2000),
@Chunk3 VARCHAR(2000),
@Chunk4 VARCHAR(2000)
SELECT @Chunk1 = '',
@Chunk2 = '',
@Chunk3 = '',
@Chunk4 = ''
IF (@len > 2000)
BEGIN
-- Let's set the right chunks
-- We already know we need two chunks so let's set the first
SELECT @Chunk1 = SUBSTRING(@SQL, 1, 2000)
-- Let's see if we need three chunks
IF (@len > 4000)
BEGIN
SELECT @Chunk2 = SUBSTRING(@SQL, 2001, 2000)
-- Let's see if we need four chunks
IF (@len > 6000)
BEGIN
SELECT @Chunk3 = SUBSTRING(@SQL, 4001, 2000)
SELECT @Chunk4 = SUBSTRING(@SQL, 6001, (@len - 6001))
END
ELSE
BEGIN
SELECT @Chunk3 = SUBSTRING(@SQL, 4001, (@len - 4001))
END
END
ELSE
BEGIN
SELECT @Chunk2 = SUBSTRING(@SQL, 2001, (@len - 2001))
END
END
-- Alright, now that we've broken it down, let's execute it
EXEC (@Chunk1 + @Chunk2 + @Chunk3 + @Chunk4)
END
вы также используете текст nvarchar. это означает, что вы должны просто иметь "N" перед вашей массивной строкой, и все! никаких ограничений больше
DELARE @SQL NVARCHAR(MAX);
SET @SQL = N'SomeMassiveString > 4000 chars...';
EXEC(@SQL);
GO
declare @p varbinary(max)
set @p = 0x
declare @local table (col text)
SELECT @p = @p + 0x3B + CONVERT(varbinary(100), Email)
FROM tbCarsList
where email <> ''
group by email
order by email
set @p = substring(@p, 2, 100000)
insert @local values(cast(@p as varchar(max)))
select DATALENGTH(col) as collen, col from @local
result collen > 8000, length col value is more than 8000 chars