Есть ли какие-либо недостатки в использовании nvarchar(MAX)?

в SQL Server 2005 есть ли какие-либо недостатки в создании всех символьных полей nvarchar(MAX) вместо явного указания длины, например nvarchar(255)? (Кроме очевидного, что вы не можете ограничить длину поля на уровне базы данных)

22 ответов


тот же вопрос был задан на форумах MSDN:

из исходного сообщения (там гораздо больше информации):

при хранении данных в столбце VARCHAR(N) значения физически сохраняются таким же образом. Но когда вы сохраняете его в столбце VARCHAR (MAX), за экраном данные обрабатываются как текстовое значение. Таким образом, при работе с a требуется дополнительная обработка Значение VARCHAR (MAX). (только если размер превышает 8000)

VARCHAR(MAX) или NVARCHAR (MAX) рассматривается как "тип большого значения". Большие типы значений обычно хранятся "вне строки". Это означает, что строка данных будет иметь указатель на другое место, где хранится "большое значение"...


Это справедливый вопрос, и он действительно заявил, Помимо очевидного...

недостаткам можно отнести:

влияние на производительность Оптимизатор запросов использует размер поля для определения наиболее эффективного плана выполнения

"1. Пространство alloction в распространяется и на страницах базы данных являются гибкими. Таким образом, при добавлении информации в поле с помощью update ваша база данных должна будет создать указатель, если новые данные длиннее, чем предыдущие. Это файлы базы данных станут фрагментированными = низкая производительность практически во всем, от индекса до удаления, обновления и вставки. " http://sqlblogcasts.com/blogs/simons/archive/2006/02/28/Why-use-anything-but-varchar_2800_max_2900_.aspx

последствия интеграции-трудно для других систем, чтобы знать, как интегрировать с вашей базой данных Непредсказуемый рост данных Возможные проблемы безопасности, например, вы можете сбой системы, занимая все дисковое пространство

там хорошая статья здесь: http://searchsqlserver.techtarget.com/tip/1,289483, sid87_gci1098157,00.html


иногда вы хотите, чтобы тип данных применял некоторый смысл к данным в нем.

скажем, например, у вас есть столбец, который действительно не должен быть длиннее, скажем, 20 символов. Если вы определяете этот столбец как VARCHAR (MAX), какое-то приложение-изгоев может вставить в него длинную строку, и вы никогда не узнаете или не сможете ее предотвратить.

в следующий раз, когда ваше приложение использует эту строку, при условии, что длина строки является скромной и разумной для домен, который он представляет, Вы будете испытывать непредсказуемый и запутанный результат.


на основании ссылки, приведенной в принятом ответе, представляется, что:

  1. 100 символов, хранящихся в nvarchar(MAX) поле будет храниться не отличается от 100 символов в элементе nvarchar(100) поле - данные будут храниться в аннотации и у вас не будет накладных расходов на чтение и запись данных из строки'. Так что не беспокойтесь.

  2. если размер больше 4000, то данные будут храниться "из строки" автоматически, что вы бы хотеть. Так что не беспокойтесь.

однако...

  1. вы не можете создать индекс на . Можно использовать полнотекстовое индексирование, но нельзя создать индекс в столбце для повышения производительности запроса. Для меня это запечатывает сделку...это определенный недостаток всегда использовать nvarchar (MAX).

вывод:

если вы хотите своего рода "универсальную длину строки" по всей вашей базе данных, которая может быть проиндексированным и который не будет тратить пространство и время доступа, тогда вы можете использовать nvarchar(4000).


Я проверил некоторые статьи и нашел полезный тестовый скрипт из этого:http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx Затем изменил его для сравнения между NVARCHAR(10) vs NVARCHAR(4000) vs NVARCHAR (MAX), и я не нахожу разницы в скорости при использовании указанных чисел, но при использовании MAX. Вы можете проверить сами. Надеюсь, это поможет.

SET NOCOUNT ON;

--===== Test Variable Assignment 1,000,000 times using NVARCHAR(10)
DECLARE @SomeString NVARCHAR(10),
        @StartTime DATETIME;
--=====         
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='10', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(4000)
DECLARE @SomeString NVARCHAR(4000),
        @StartTime DATETIME;
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='4000', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(MAX)
DECLARE @SomeString NVARCHAR(MAX),
        @StartTime DATETIME;
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='MAX', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO

думайте об этом как о еще одном уровне безопасности. Вы можете спроектировать таблицу без связей внешнего ключа - совершенно допустимых-и обеспечить существование связанных сущностей полностью на бизнес-уровне. Однако внешние ключи считаются хорошей практикой проектирования, поскольку они добавляют еще один уровень ограничения в случае, если что-то испортится на бизнес-уровне. То же самое касается ограничения размера поля и не использования varchar MAX.


причина не использовать max или текстовые поля заключается в том, что вы не можете выполнить онлайн перестроение индекса т. е. перестроить с ONLINE= ON даже с SQL Server Enterprise Edition.


единственная проблема, которую я обнаружил, заключалась в том, что мы разрабатываем наши приложения на SQL Server 2005, и в одном случае мы должны поддерживать SQL Server 2000. Я только что узнал,трудный путь что SQL Server 2000 не нравится параметр MAX для varchar или nvarchar.


плохая идея, когда вы знаете, поле будет в заданном диапазоне - от 5 до 10 символов например. Думаю, я бы использовал Макса, если бы не был уверен, какой будет длина. Например, номер телефона никогда не будет больше определенного количества символов.

можете ли вы честно сказать, что вы не уверены в приблизительных требованиях к длине для каждого поля в вашей таблице?

Я понимаю вашу точку зрения, хотя - есть некоторые поля, которые я бы, безусловно, рассмотреть вопрос об использовании varchar (max).

интересно документы MSDN подведите итог довольно хорошо:

используйте varchar, когда размеры записи данных столбцов значительно различаются. Используйте varchar(Макс), когда размеры записи данных столбцов значительно различаются, а размер может превышать 8000 байт.

здесь интересная дискуссия по этому вопросу здесь.


задача базы данных-хранить данные, чтобы они могли использоваться предприятием. Часть решений, полезных данных, сделать это имеет смысл. Разрешение кому-то вводить неограниченное количество символов для своего имени не обеспечивает значимых данных.

построение этих ограничений на бизнес-уровне-хорошая идея, но это не гарантирует, что база данных останется неповрежденной. Единственный способ гарантировать, что данные правила не нарушаются-это соблюдение они на самом низком уровне, возможном в базе данных.


одна из проблем заключается в том, что если вам приходится работать с несколькими версиями SQL Server, MAX не всегда будет работать. Поэтому, если вы работаете с legacy DB или любой другой ситуацией, которая включает в себя несколько версий, вам лучше быть очень осторожным.


Как было отмечено выше, это в первую очередь компромисс между памятью и производительностью. По крайней мере в большинстве случаев.

однако существует по крайней мере один другой фактор, который следует учитывать при выборе n/varchar(Max) над n/varchar(n). Будут ли данные индексироваться (например, фамилия)? Поскольку определение MAX считается LOB, то все, что определено как MAX, недоступно для индексирования. и без индекса, любой поиск, включающий данные как предикат в WHERE предложение будет принудительно проверено на полную таблицу, что является худшей производительностью, которую вы можете получить для поиска данных.


1) SQL server должен будет использовать больше ресурсов(выделенная память и время процессора) при работе с nvarchar(max) vs nvarchar (n), где n-число, специфичное для поля.

2) Что это означает в отношении производительности?

в SQL Server 2005 я запросил 13 000 строк данных из таблицы с 15 столбцами nvarchar (max). Я несколько раз синхронизировал запросы, а затем изменил столбцы на nvarchar (255) или меньше.

запросы до оптимизация в среднем составила 2,0858 секунды. Запросы после изменения возвращаются в среднем за 1,90 секунды. Это было около 184 миллисекунд улучшения базового запроса select *. Это улучшение на 8,8%.

3) мои результаты согласуются с несколькими другими статьями, в которых указано, что существует разница в производительности. В зависимости от базы данных и запроса процент улучшения может варьироваться. Если у вас нет много одновременных пользователей или очень много записи, то разницы в производительности не будет проблемой для вас. Однако разница в производительности будет увеличиваться по мере увеличения количества записей и одновременных пользователей.


У меня был udf, который проложил строки и поставил вывод на varchar(max). Если это было использовано непосредственно вместо возврата к соответствующему размеру для корректируемого столбца, производительность была очень низкой. Я закончил тем, что поместил udf в произвольную длину с большой запиской, вместо того, чтобы полагаться на всех вызывающих udf, чтобы повторно привести строку к меньшему размеру.


интересные ссылки: зачем использовать VARCHAR, когда вы можете использовать текст?

речь идет о PostgreSQL и MySQL, поэтому анализ производительности отличается, но логика "эксплицитности" все еще сохраняется: зачем заставлять себя всегда беспокоиться о чем-то, что имеет отношение к небольшому проценту времени? Если вы сохранили адрес электронной почты в переменной, вы бы использовали "строку", а не "строку, ограниченную 80 символами".


устаревшей системы поддержки. Если у вас есть система, которая использует данные, и ожидается, что она будет определенной длины, то база данных является хорошим местом для обеспечения длины. Это не идеально, но устаревшие системы иногда не идеальны. =P


Если все данные в строке (для всех столбцов) никогда бы разумно взять 8000 или меньше символов, то дизайн на уровне данных должен осуществить это.

компонент database engine намного эффективнее сохраняет все из хранилища blob. Чем меньше вы можете ограничить ряд, тем лучше. Чем больше строк вы можете втиснуть в страницу, тем лучше. База данных просто работает лучше, когда ей нужно получить доступ к меньшему количеству страниц.


мои тесты показали, что существуют различия при выборе.

CREATE TABLE t4000 (a NVARCHAR(4000) NULL);

CREATE TABLE tmax (a NVARCHAR(MAX) NULL);

DECLARE @abc4 NVARCHAR(4000) = N'ABC';

INSERT INTO t4000
SELECT TOP 1000000 @abc4
    FROM
    master.sys.all_columns ac1,
    master.sys.all_columns ac2;

DECLARE @abc NVARCHAR(MAX) = N'ABC';

INSERT INTO tmax
SELECT TOP 1000000 @abc
    FROM
    master.sys.all_columns ac1,
    master.sys.all_columns ac2;

SET STATISTICS TIME ON;
SET STATISTICS IO ON;

SELECT * FROM dbo.t4000;
SELECT * FROM dbo.tmax;

основной недостаток я вижу в том, что скажем, у вас есть это:

что дает вам больше информации о данных, необходимых для пользовательского интерфейса?

этой

            CREATE TABLE [dbo].[BusData](
                [ID] [int] IDENTITY(1,1) NOT NULL,
                [RecordId] [nvarchar](MAX) NULL,
                [CompanyName] [nvarchar](MAX) NOT NULL,
                [FirstName] [nvarchar](MAX) NOT NULL,
                [LastName] [nvarchar](MAX) NOT NULL,
                [ADDRESS] [nvarchar](MAX) NOT NULL,
                [CITY] [nvarchar](MAX) NOT NULL,
                [County] [nvarchar](MAX) NOT NULL,
                [STATE] [nvarchar](MAX) NOT NULL,
                [ZIP] [nvarchar](MAX) NOT NULL,
                [PHONE] [nvarchar](MAX) NOT NULL,
                [COUNTRY] [nvarchar](MAX) NOT NULL,
                [NPA] [nvarchar](MAX) NULL,
                [NXX] [nvarchar](MAX) NULL,
                [XXXX] [nvarchar](MAX) NULL,
                [CurrentRecord] [nvarchar](MAX) NULL,
                [TotalCount] [nvarchar](MAX) NULL,
                [Status] [int] NOT NULL,
                [ChangeDate] [datetime] NOT NULL
            ) ON [PRIMARY]

Или Это?

            CREATE TABLE [dbo].[BusData](
                [ID] [int] IDENTITY(1,1) NOT NULL,
                [RecordId] [nvarchar](50) NULL,
                [CompanyName] [nvarchar](50) NOT NULL,
                [FirstName] [nvarchar](50) NOT NULL,
                [LastName] [nvarchar](50) NOT NULL,
                [ADDRESS] [nvarchar](50) NOT NULL,
                [CITY] [nvarchar](50) NOT NULL,
                [County] [nvarchar](50) NOT NULL,
                [STATE] [nvarchar](2) NOT NULL,
                [ZIP] [nvarchar](16) NOT NULL,
                [PHONE] [nvarchar](18) NOT NULL,
                [COUNTRY] [nvarchar](50) NOT NULL,
                [NPA] [nvarchar](3) NULL,
                [NXX] [nvarchar](3) NULL,
                [XXXX] [nvarchar](4) NULL,
                [CurrentRecord] [nvarchar](50) NULL,
                [TotalCount] [nvarchar](50) NULL,
                [Status] [int] NOT NULL,
                [ChangeDate] [datetime] NOT NULL
            ) ON [PRIMARY]

одним из недостатков является то, что вы будете разрабатывать непредсказуемую переменную, и вы, вероятно, проигнорируете вместо того, чтобы воспользоваться внутренней структурой данных SQL Server, постепенно состоящей из строк, страниц и экстентов.

Что заставляет меня думать о - это структура данных, расстановка В C, и это знание выравнивания обычно считается хорошей вещью (TM). Похожая идея, другой контекст.

страница MSDN для страницы и экстенты

страница MSDN для Данные Переполнения Строк


Это вызовет проблемы с производительностью, хотя это может никогда не вызвать никаких реальных проблем, если ваша база данных мала. Каждая запись займет больше места на жестком диске, и база данных должна будет прочитать больше секторов диска, Если вы ищете сразу много записей. Например, небольшая запись может вместить 50 в сектор, а большая запись-5. Вам нужно прочитать в 10 раз больше данных с диска с помощью записи.


это сделает дизайн экрана сложнее, поскольку вы больше не сможете предсказать, насколько широкими должны быть ваши элементы управления.