В SQL Server 2005 есть ли какие-либо недостатки в том, чтобы сделать все символьные поля nvarchar (MAX) вместо того, чтобы явно указывать длину, например nvarchar (255)? (Помимо очевидного, что вы не можете ограничить длину поля на уровне базы данных)
Я просто не понимаю, почему вы хотите, чтобы кто-то вводил имя, состоящее из 8000+ символов.
Проверьте это: stackoverflow.com/questions/2009694/…
Ваше обновление должно быть отдельным ответом на этот вопрос.
answer-in-question перемещен к правильному ответу, поскольку первоначальный автор этого не сделал. stackoverflow.com/a/35177895/10245 Я считаю, что 7 лет - это достаточно :-)
Хорошее чтение: МАКСИМАЛЬНЫЕ типы данных ЧТО? Брент Озар: brentozar.com/archive/2016/10/max-data-types
Еще одна статья, в которой сравнивается производительность между varchar (max) и varchar (n): rusanu.com/2010/03/22/…


Единственная проблема, которую я обнаружил, заключалась в том, что мы разрабатываем наши приложения на SQL Server 2005, и в одном случае мы должны поддерживать SQL Server 2000. Я только что узнал, что SQL Server 2000 не любит параметр MAX для varchar или nvarchar .
Так почему бы просто не развиваться по наименьшему общему знаменателю?
Это справедливый вопрос, и он заявил, помимо очевидного ...
К недостаткам можно отнести:
Последствия для производительности Оптимизатор запросов использует размер поля для определения наиболее эффективного плана выполнения.
"1. Распределение пространства в расширении и страницах базы данных является гибким. Таким образом, при добавлении информации в поле с помощью обновления ваша база данных должна будет создать указатель, если новые данные длиннее, чем предыдущие вставленные. Это файлы базы данных будут стать фрагментированным = низкая производительность практически во всем, от индекса до удаления, обновления и вставки ». 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
+1 Для интеграции и безопасности. Это оригинальный угол, который следует учитывать, когда в большинстве других ответов говорится о производительности. В связи с последствиями интеграции любые инструменты (например, составители отчетов или конструкторы форм), использующие метаданные для обеспечения разумных размеров элементов управления по умолчанию, потребовали бы гораздо больше работы, если бы все столбцы были varchar(max).
Интеграция по базе данных - самая нелепая вещь, что я знаю. Если это только импорт, сделанный один раз, вы можете проверить данные раньше с помощью функции LEN.
Тот же вопрос был задан на форумах MSDN:
Из исходного сообщения (там гораздо больше информации):
When you store data to a VARCHAR(N) column, the values are physically stored in the same way. But when you store it to a VARCHAR(MAX) column, behind the screen the data is handled as a TEXT value. So there is some additional processing needed when dealing with a VARCHAR(MAX) value. (only if the size exceeds 8000)
VARCHAR(MAX) or NVARCHAR(MAX) is considered as a 'large value type'. Large value types are usually stored 'out of row'. It means that the data row will have a pointer to another location where the 'large value' is stored...
Итак, должен быть вопрос, есть ли разница между использованием N / VARCHAR (MAX) и N / TEXT?
Если я правильно помню, разве они не хранятся вне очереди, только если размер превышает 8 КБ?
Это сделка между пространством и производительностью. VARCHAR (MAX) с использованием указателей разумно расходует пространство и выполняет дополнительную обработку для этого интеллекта. Я думаю, что решение во многом зависит от разницы в стоимости хранения и вычислительной мощности.
Я прочитал ответ как «нет, в использовании N/VARCHAR(MAX) нет недостатков», потому что дополнительная обработка выполняется «только в том случае, если размер превышает 8000». Таким образом, вы несете затраты только при необходимости, а ваша база данных - менее строгий. Я неправильно это читаю? Похоже, вам почти всегда нужен N/VARCHAR(MAX), а не N/VARCHAR(1-8000) ...
Мертвая ссылка выше - рабочая ссылка для вопроса в MSDN - social.msdn.microsoft.com/Forums/en-US/sqlgetstarted/thread/…
К сожалению, у этого ответа есть ряд проблем. Из-за этого граница 8k выглядит как магическое число, это не так, значение выталкивается из строки на основе большего количества факторов, включая sp_tableoptions: msdn.microsoft.com/en-us/library/ms173530.aspx. Типы VARCHAR (255) также могут быть вытеснены из строки, упомянутые «накладные расходы» могут быть точно такими же для MAX и 255. Он сравнивает типы MAX с типами TEXT, когда они различны по мере их получения (совершенно другой API для управления, другое хранилище и т. д.). Не упоминаются фактические различия: нет индекса, нет онлайн-операций с типами MAX.
Разве это не сумма размеров всех столбцов в строке, которая должна была бы превысить 8 КБ, чтобы она была вытолкнута во внешнее хранилище?
@RemusRusanu Так не могли бы вы прояснить, о чем вы говорите? Вы намекаете, что использование MAX - плохая идея / есть серьезные проблемы?
@niico, да, max ужасно использовать, если вы не ожидаете, что будет сохранено более (400 или 800 символов, так как вы не можете индексировать поле. Это необходимо для полей, где требуется большой текст, но использовать его вместо этого ужасная идея правильного размера поля.
@HLGEM: Объясните свои рассуждения. Я не верю, что кто-то здесь сказал то, что вы называете «фактом».
Попробуй это. СОЗДАТЬ ТАБЛИЦУ varcharTest (id INT, myString VARCHAR (MAX)) СОЗДАТЬ ИНДЕКС idx_wontwork ON varcharTest (myString)
У меня был udf, который дополнял строки и помещал вывод в varchar (max). Если бы это использовалось напрямую, вместо того, чтобы возвращаться к соответствующему размеру регулируемой колонны, производительность была бы очень низкой. Я закончил тем, что поместил udf в произвольную длину с большой примечанием, вместо того, чтобы полагаться на всех вызывающих udf, чтобы повторно преобразовать строку к меньшему размеру.
Это вызовет проблемы с производительностью, хотя может никогда не вызвать реальных проблем, если ваша база данных мала. Каждая запись будет занимать больше места на жестком диске, и базе данных потребуется читать больше секторов диска, если вы просматриваете множество записей одновременно. Например, небольшая запись может уместиться в 50 секторов, а большая запись может уместиться в 5. Вам нужно будет прочитать в 10 раз больше данных с диска, используя большую запись.
-1. Строка длиной 100, хранящаяся в столбце nvarchar(max), занимает не больше дискового пространства, чем если бы она была в столбце nvarchar(100).
То, что вы описываете, правильно, если размер хранимых данных больше, но этот вопрос касается того, влияет ли тип данных на производительность или другие соображения.
Это усложнит дизайн экрана, так как вы больше не сможете предсказать, насколько широкими должны быть элементы управления.
Интересная ссылка: Зачем использовать VARCHAR, если можно использовать ТЕКСТ?
Речь идет о PostgreSQL и MySQL, поэтому анализ производительности отличается, но логика «явности» все еще сохраняется: зачем заставлять себя всегда беспокоиться о чем-то, что актуально в небольшом проценте случаев? Если вы сохранили адрес электронной почты в переменной, вы должны использовать «строку», а не «строку, ограниченную 80 символами».
Это похоже на утверждение, что у вас не должно быть проверочных ограничений, чтобы убедиться, что возраст человека не является отрицательным числом.
Я вижу разницу между правильностью данных и оптимизацией производительности.
Одна из проблем заключается в том, что если вам приходится работать с несколькими версиями SQL Server, MAX не всегда будет работать. Поэтому, если вы работаете с устаревшими базами данных или в любой другой ситуации, которая включает несколько версий, вам лучше быть очень осторожными.
Я думаю, что невысказанное предположение со стороны OP состоит в том, что он имеет дело исключительно с экземплярами 2005+, и что его приложениям не нужно работать с версиями 2000 (или, ack, ниже). Я полностью согласен с вами, если есть необходимость в поддержке более старых версий!
Джон Руди: Могу представить, что это так, я просто знаю, что сам столкнулся с этими препятствиями, хотя не думал, что собираюсь.
На самом деле это распространенная проблема с современными материалами из-за SQL CE 4, который не поддерживает типы столбцов MAX, поэтому совместимость является проблемой.
Иногда вам нужно, чтобы тип данных придавал некоторый смысл содержащимся в нем данным.
Скажем, например, у вас есть столбец, длина которого не должна превышать, скажем, 20 символов. Если вы определите этот столбец как VARCHAR (MAX), какое-нибудь мошенническое приложение может вставить в него длинную строку, и вы никогда не узнаете об этом или не найдете способ предотвратить это.
В следующий раз, когда ваше приложение будет использовать эту строку, при условии, что длина строки является скромной и разумной для домена, который она представляет, вы получите непредсказуемый и запутанный результат.
Я согласен с этим и некоторыми другими комментариями, но по-прежнему считаю, что это ответственность бизнес-уровня. К тому времени, когда он достигнет уровня базы данных, он должен щелкнуть приветствие и сохранить значение, каким бы смехотворно длинным оно ни было. Я думаю, что здесь действительно важно то, что я думаю, что примерно в 90% случаев, когда разработчик указывает varchar (255), его намерение на самом деле не 255 символов, а какое-то неопределенное среднее значение длины. И учитывая компромисс между необоснованно большими значениями в моей базе данных и непредвиденными исключениями, я возьму большие значения.
Не указывайте varchar (255), если вы хотите, чтобы ограничение было короче.
Если они указывают VARCHAR (255), чтобы указать некоторую неизвестную длину, то это их вина в том, что они неправильно исследовали то, что они разрабатывают. Решение состоит в том, чтобы разработчик выполнял свою работу, а не в том, чтобы база данных допускала необоснованные значения.
не помогло автору. он явно исключил этот вопрос, на который вы ответили.
@ Крис Беренс: Я не согласен; схема базы данных является часть бизнес-логики. Выбор таблиц, отношений, полей и типов данных - это все бизнес-логика, и для обеспечения соблюдения правил этой бизнес-логики стоит использовать СУБД. По одной причине очень редко бывает, что к базе данных обращается только один уровень приложения; например, у вас могут быть инструменты импорта и извлечения данных, которые обходят основной бизнес-уровень, а это означает, что вам действительно нужна БД, чтобы обеспечивать соблюдение правил.
Если вам не нужно хранить длинные строки или вы действительно хотите, чтобы они хранились, то лучше усилить смысл данных. Например, если вы сохраняете поле PostCode, разрешите ли вы кому-нибудь вводить сотни или тысячи символов, когда оно должно быть максимум 10, скажем. - Максимальный размер должен быть подтвержден на всех уровнях, клиентском, бизнес-уровне И базе данных. При использовании подхода Model First, такого как C# и Entity Framework, вы можете определить свой maxsize в модели и применить его к базе данных, бизнес-логике и проверке клиента (с подобными проверке jquery). Используйте только nvarchar (max), если это действительно необходимо
Плохая идея, когда вы знаете, что поле будет в заданном диапазоне от 5 до 10 символов, например. Думаю, я бы использовал max только в том случае, если не был уверен, какой будет длина. Например, телефонный номер никогда не может содержать больше определенного количества символов.
Можете ли вы честно сказать, что не уверены в примерных требованиях к длине каждого поля в вашей таблице?
Я понимаю вашу точку зрения - есть некоторые поля, которые я бы определенно рассмотрел с помощью varchar (max).
Интересно, что Документы MSDN довольно хорошо резюмирует:
Use varchar when the sizes of the column data entries vary considerably. Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
Есть интересное обсуждение проблемы здесь.
Для таких вещей, как телефонные номера, мне было бы гораздо удобнее использовать поле char вместо varchar. Пока вы поддерживаете стандарт в своем хранилище и вам не нужно беспокоиться о телефонных номерах из разных стран, вам никогда не понадобится переменное поле для чего-то вроде номера телефона (10 без форматирования) или почтового индекса (5 или 9-10, если добавить последние четыре цифры) и т. д.
Я имел в виду телефонные номера, длина которых может быть разной. Возможно, мне стоит поставить это в ответ. Все, что имеет фиксированную длину, я бы использовал поле char.
Или, возможно, я должен был сказать в своем комментарии nchar или char. :-)
Количество символов в телефонном номере в значительной степени является бизнес-требованием. Если вам необходимо сохранить код международного стандарта вместе с номером, он может быть больше 10. Или в какой-то части мира для номера телефона может быть более 10 цифр. Представьте себе переход с IPV4 на IPV6. Никто бы не стал утверждать, что в старые добрые времена IPV4 нам нужно было больше 12 цифр. Это может не иметь места, если IPV6 станет преобладающим. Это снова изменение бизнес-правил с течением времени. Как сказано, перемены - единственное, чего мы можем ожидать постоянно :)
Будьте осторожны, предполагая, что вы знаете, сколько символов может быть в поле телефонного номера или какие символы они будут. Если система не использует эти данные для фактического дозвона (в этом случае вы должны быть строгими в отношении форматов), тогда пользователь может законно поместить туда неожиданно длинные строки, например. «0123 456 78910 спросите у стойки регистрации добавочный номер 45, а затем переведите его на Джеймса».
Телефонные номера - хороший контрпример. Средний номер телефонного номера со временем явно увеличивается в размерах.
Думайте об этом как о еще одном уровне безопасности. Вы можете спроектировать свою таблицу без отношений внешнего ключа - что совершенно корректно - и обеспечить существование связанных сущностей полностью на бизнес-уровне. Однако внешние ключи считаются хорошей практикой проектирования, потому что они добавляют еще один уровень ограничений на случай, если что-то не так на бизнес-уровне. То же самое касается ограничения размера поля и без использования varchar MAX.
поддержка устаревших систем. Если у вас есть система, которая использует данные, и ожидается, что она будет определенной длины, тогда база данных - хорошее место для обеспечения длины. Это не идеально, но устаревшие системы иногда не идеальны. = P
Если все данные в строке (для всех столбцов) никогда не будут разумно занимать 8000 или меньше символов, тогда дизайн на уровне данных должен обеспечить это.
Ядро базы данных намного эффективнее, позволяя хранить все вне хранилища BLOB-объектов. Чем меньше вы можете ограничить строку, тем лучше. Чем больше строк вы сможете втиснуть на страницу, тем лучше. База данных просто работает лучше, когда ей требуется доступ к меньшему количеству страниц.
Причина, по которой НЕ следует использовать поля max или text, заключается в том, что вы не можете выполнить перестройка индекса в Интернете, т.е. REBUILD WITH ONLINE = ON даже с SQL Server Enterprise Edition.
Это же ограничение действует и для типа поля TEXT, поэтому вы все равно должны использовать VARCHAR (MAX) вместо TEXT.
из-за этого мы не смогли перестроить наш кластеризованный индекс. это стоило нам много места на диске, пока мы не смогли извлечь столбец в его собственную таблицу (мы не могли позволить себе блокировать таблицу более чем на 7 секунд)
Задача базы данных - хранить данные, чтобы их могло использовать предприятие. Частью того, чтобы сделать эти данные полезными, является их значимость. Разрешение кому-либо вводить неограниченное количество символов для своего имени не обеспечивает значимых данных.
Встраивание этих ограничений в бизнес-уровень - хорошая идея, но это не гарантирует, что база данных останется нетронутой. Единственный способ гарантировать, что правила данных не нарушаются, - это обеспечить их соблюдение на самом низком уровне базы данных.
ИМО, ограничения на длину данных основаны исключительно на бизнес-правилах, которые могут меняться с течением времени по мере роста приложения. Изменить бизнес-правила в бизнес-логике проще, чем на уровне базы данных. Итак, я думаю, что база данных должна быть достаточно гибкой и не должна быть привязана к бизнес-правилам, таким как максимально допустимая длина имени, которая очень сильно зависит от той части мира, в которой вы живете, в которой живет ваш пользователь.
Главный недостаток, который я вижу, заключается в том, что, допустим, у вас есть это:
Какой из них дает вам больше всего информации о данных, необходимых для пользовательского интерфейса?
Этот
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]
Я бы предпочел, чтобы бизнес-логика говорила мне, что имя компании может содержать не более 50 символов, а не полагаться на таблицу базы данных для этой информации.
Я согласен с Джеффом. Я не думаю, что хранилище постоянства - подходящее место для определения ваших бизнес-правил. А в многоуровневой архитектуре ваш пользовательский интерфейс даже не знает о слое постоянства.
Если, конечно, вы не используете значение, ограниченное определенным размером, например код ISO для страны.
При чем здесь таблица def? У вас все еще может быть бизнес-логика. Я думаю, что ваша точка зрения не имеет смысла относительно того, как устроен стол. Если вы все еще хотите разработать какое-то определение на своем бизнес-уровне, пусть будет так. Хотя было бы больше смысла использовать сохраненную процедуру в любом случае на бизнес-уровне; не таблица def ??
Это кажется непопулярным, но я согласен с Карлосом, если db устанавливает максимальный размер, тогда вы можете чувствовать себя комфортно во всех слоях, которые вы создаете поверх него, с чем вам, вероятно, придется иметь дело. Это особенно важно, если у вас есть несколько систем, записывающих в вашу базу данных.
@TimAbell Я вижу это немного по-другому. Во многих языках, таких как C#, мы используем такие типы, как string, которые также более или менее неограниченны. Ограничение длины было необходимо во времена AS / 400 и COBOL, но сегодня это уже не так. Вместо этого часто возникают проблемы, когда база данных используется дольше. Лучше использовать какое-то форматирование в пользовательском интерфейсе, когда требуется особое ограничение.
@Khan, бизнес-уровень - это как раз неподходящее место для этих ограничений, так как он будет неоднократно заменяться в жизни базы данных. Люди, которые не устанавливают надлежащих ограничений в базе данных, к которой они принадлежат, в конечном итоге сталкиваются с проблемами целостности данных.
Одним из недостатков является то, что вы будете проектировать вокруг непредсказуемой переменной и, вероятно, проигнорируете вместо того, чтобы использовать преимущества внутренней структуры данных SQL Server, которая постепенно состоит из строк, страниц и экстентов.
Это заставляет меня думать о выравнивание структуры данных в C и о том, что осведомленность о выравнивании обычно считается хорошей вещью (TM). Похожая идея, другой контекст.
Страница MSDN для Страницы и экстенты
Страница MSDN для Данные о переполнении строк
1) SQL-серверу придется использовать больше ресурсов (выделенная память и время процессора) при работе с 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) Мои результаты совпадают с результатами нескольких других статей, в которых указывалось, что была разница в производительности. В зависимости от вашей базы данных и запроса процент улучшения может варьироваться. Если у вас не так много одновременных пользователей или очень много записей, разница в производительности не будет для вас проблемой. Однако разница в производительности будет увеличиваться по мере увеличения количества записей и одновременных пользователей.
Я проверил несколько статей и нашел здесь полезный тестовый скрипт: http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx Затем изменил его, чтобы сравнить между NVARCHAR (10) против NVARCHAR (4000) против 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
Это интересно. На моей коробке кажется, что MAX в 4 раза медленнее.
Я работаю над некоторыми связанными сценариями, чтобы получить более точный ответ, и надеюсь поделиться с вами как можно скорее.
Новые результаты на SQL Server 2012: 10 в два раза медленнее, чем 4k, а MAX в 5,5 раз медленнее, чем 4k.
В большинстве случаев это неявное приведение от varchar к nvarchar (max). Попробуйте это: DECLARE \ @SomeString NVARCHAR (MAX), \ @abc NVARCHAR (max) = N'ABC ', \ @StartTime DATETIME; ВЫБРАТЬ @startTime = GETDATE (); ВЫБЕРИТЕ TOP 1000000 \ @SomeString = \ @abc FROM master.sys.all_columns ac1, master.sys.all_columns ac2; ВЫБЕРИТЕ testTime = 'MAX', Продолжительность = DATEDIFF (мс, \ @ StartTime, GETDATE ()); Пришлось вставить \ перед переменными, чтобы опубликовать.
@Kvasi Это хороший момент, Спасибо, я изучал, но я тестировал новое время продолжительности, и кажется, что разница в продолжительности будет короче, но она еще существует. Пожалуйста, проверьте все разделы с параметрами NVARCHAR, которые вы вызвали \ @abc, чтобы увидеть разницу во времени. думаю, что в реальном случае и в большом SQL-запросе мы не можем использовать никакую строку в типе NVARCHAR (MAX).
SQL Server 2014 на SSD: 150, 156, 716 (10, 4000, MAX).
Спасибо за добавление реальных цифр в это обсуждение. Мы часто забываем, что создание тестового примера - это самый быстрый способ понимания.
Я получаю аналогичные, немного более высокие числа для @Maxim, хотя мой SQL-сервер находится в отдельном ящике в той же комнате. (SQL Server 2008 / R2 работает под управлением Windows Server 2008 / R2.)
Судя по ссылке, указанной в принятом ответе, кажется, что:
100 символов, хранящихся в поле nvarchar(MAX), будут сохранены так же, как 100 символов в поле nvarchar(100) - данные будут храниться внутри, и у вас не будет накладных расходов на чтение и запись данных «вне строки». Так что не беспокойтесь.
Если размер больше 4000, данные будут автоматически сохраняться вне строки, что вам и нужно. Так что здесь тоже не о чем беспокоиться.
Тем не мение...
nvarchar(MAX). Вы можете использовать полнотекстовое индексирование, но вы не можете создать индекс для столбца для повышения производительности запроса. Для меня это закрепляет сделку ... всегда использовать nvarchar (MAX) - явный недостаток.Заключение:
Если вам нужна «универсальная длина строки» для всей базы данных, которую можно индексировать и которая не будет тратить впустую пространство и время доступа, тогда вы можете использовать nvarchar(4000).
fyi, это было изменение, добавленное к исходному вопросу, которое должно было быть опубликовано в качестве ответа
Спасибо, для меня это окончательный ответ. Я задавал себе то же самое - почему бы не использовать nvarchar(max) постоянно - как string в C#? - но пункт 3) (проблема индекса) дает ответ.
Добавил правку. В качестве «универсальной длины строки» вы всегда можете использовать nvarchar(4000).
@SQLGeorge См. Этот отличный ответ Мартин Смит о влиянии объявления столбцов шире, чем когда-либо, на производительность запросов.
@billinkc Спасибо, отличная статья. Итак, размер действительно влияет на производительность. Я еще раз отредактирую ответ.
Как было указано выше, это прежде всего компромисс между объемом памяти и производительностью. По крайней мере, в большинстве случаев.
Однако есть по крайней мере еще один фактор, который следует учитывать при выборе n / varchar (Max) вместо n / varchar (n). Будут ли данные индексироваться (например, фамилия)? Поскольку определение MAX считается LOB, то все, что определено как MAX, недоступно для индексации. а без индекса любой поиск, включающий данные в качестве предиката в предложении WHERE, будет вынужден выполнять сканирование полной таблицы, что является худшей производительностью, которую вы можете получить при поиске данных.
Мои тесты показали, что при выборе есть отличия.
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;
сначала я подумал об этом, но потом подумал еще раз. Это влияет на производительность, но в равной степени это служит формой документации, чтобы иметь представление о том, какого размера поля на самом деле. И он применяется, когда эта база данных находится в более крупной экосистеме. На мой взгляд, главное - быть снисходительным, но только в пределах разумного.
Хорошо, вот мои чувства просто по вопросу о логике бизнес-уровня и уровня данных. Это зависит от того, является ли ваша БД общим ресурсом между системами, которые разделяют бизнес-логику, тогда, конечно, кажется естественным местом для обеспечения такой логики, но это не ЛУЧШИЙ способ сделать это, ЛУЧШИЙ способ - предоставить API, это позволяет взаимодействие, которое необходимо протестировать, и сохраняет бизнес-логику на своем месте, сохраняет развязку систем, поддерживает развязку уровней внутри системы. Если, однако, ваша база данных должна обслуживать только одно приложение, тогда давайте подумаем AGILE, что теперь правда? дизайн на данный момент. Если и когда такой доступ необходим, предоставьте API для этих данных.
однако очевидно, что это просто идеальный вариант: если вы работаете с существующей системой, скорее всего, вам нужно будет сделать это по-другому, по крайней мере, в краткосрочной перспективе.
Начиная с SQL Server 2019, NVARCHAR (МАКС.) по-прежнему не поддерживает SCSU «Сжатие Unicode» - даже при хранении с использованием встроенного хранилища данных. SCSU был добавлен в SQL Server 2008 и применяется к любым таблицам и индексам, сжатым ROW / PAGE.
Таким образом, NVARCHAR (MAX) может принимать до двух раз больше физического дискового пространства как поле NVARCHAR (1..4000) с тем же текстовым содержимым+ - даже когда нет хранится в LOB. Отходы, не относящиеся к SCSU, зависят от представленных данных и языка.
SQL Server uses an implementation of the Standard Compression Scheme for Unicode (SCSU) algorithm to compress Unicode values that are stored in row or page compressed objects. For these compressed objects, Unicode compression is automatic for nchar(n) and nvarchar(n) columns [and is never used with nvarchar(max)].
С другой стороны, сжатие PAGE (с 2014 года) по-прежнему применяется к столбцам NVARCHAR (MAX) если, они записываются как данные In-Row ... поэтому отсутствие SCSU ощущается как «отсутствие оптимизации». В отличие от SCSU, результаты сжатия страницы могут сильно различаться в зависимости от общих начальных префиксов (т. Е. Повторяющихся значений).
Однако использование NVARCHAR (MAX) по-прежнему может быть «быстрее» даже при более высоких затратах ввода-вывода с такими функциями, как OPENJSON, из-за исключения неявного преобразования. Эти накладные расходы на неявное преобразование зависят от относительной стоимости использования и от того, касаются ли поля до или после фильтрации. Та же проблема преобразования существует при использовании параметров сортировки UTF-8 2019 в столбце VARCHAR (MAX).
Использование NVARCHAR (1-4000) также требует N * 2 байтов из ~ 8000 байтовой квоты строки, в то время как NVARCHAR (MAX) требует только 24 байта. Общий дизайн и использование необходимо рассматривать вместе, чтобы учесть конкретные детали реализации.
+ В моей базе данных / данных / схеме, используя два столбца (объединенные при чтении), можно было сократить использование дискового пространства примерно на 40%, при этом все еще поддерживая переполнение текстовых значений. SCSU, несмотря на свои недостатки, является удивительно умным и малоиспользуемым методом хранения Unicode с более эффективным использованием пространства.
Та же логика может быть применена к языкам программирования. Почему бы не вернуться к старому варианту VB6 для всех наших данных? Я не думаю, что наличие системы сдержек и противовесов более чем в одном месте обязательно плохо.