EF Code First использует nvarchar (max) для всех строк. Повлияет ли это на производительность запросов?

29

У меня есть несколько баз данных, созданных с использованием Entity Framework Code First; приложения работают, и в целом я очень доволен тем, что мне позволяет Code First. Я программист первый, а второй администратор по необходимости. Я читаю о DataAttributes для дальнейшего описания в C #, что я хочу, чтобы база данных делала; и мой вопрос: какое наказание я буду есть, имея эти nvarchar(max)строки в моей таблице (см. пример ниже)?

В этой конкретной таблице есть несколько столбцов; в C # они определены так:

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Message { get; set; }
    public string Source { get; set; }
    public DateTime Generated { get; set; }
    public DateTime Written { get; set; }

Я ожидаю выполнить запрос и / или сортировку на основе имени, источника, сгенерированного и написанного. Я ожидаю, что Имя и Источник будут иметь длину 0-50 символов, иногда до 150. Я ожидаю, что эта таблица будет довольно маленькой (<100 тыс. Строк), но со временем значительно увеличится (> 1 млн. Строк). Очевидно, что сообщение может быть маленьким или большим, и, вероятно, не будет запрашиваться.

Что я хочу знать, есть ли снижение производительности для моих столбцов «Имя» и «Источник», которые определяются, nvarchar(max)когда я никогда не ожидаю, что они будут длиннее 150 символов?

Nate
источник
5
Похоже , вам нужно применить либо [MaxLength]или [StringLength]атрибуты. Некоторые дополнительные возможные негативные факторы слишком широких столбцов упоминаются в ответе @ PaulWhite здесь
Martin Smith,
3
ДА , использование varchar(max)везде повредит вашей производительности - не делайте этого! Используйте соответствующие типы данных - используйте varchar(max) ТОЛЬКО, если вам действительно нужно более 8000 символов! (Я никогда не видел, чтобы имя человека или адрес электронной почты были такими длинными!) - Смотрите, в чем смысл использования VARCHAR (n)? для получения дополнительной информации
marc_s
@marc_s Отличная ссылка. Я знаю, что это ухудшает производительность. Когда я определяю свои собственные таблицы с помощью SQL, я использую varchar (n). Мой вопрос был больше о том, насколько это влияет на производительность (хотя я понимаю, что опубликованные сообщения не совсем ясны).
Nate

Ответы:

24

Более крупные элементы данных nvarchar (max) (более 8000 байт или около того) будут перетекать в хранилище текста и потребовать дополнительного ввода-вывода. Меньшие предметы будут храниться в ряд. Есть варианты, которые управляют этим поведением - см. Эту статью MSDN для получения дополнительной информации.

При хранении в строке значительного снижения производительности ввода-вывода нет; при обработке типа данных могут возникнуть дополнительные затраты ресурсов процессора, но, скорее всего, они будут незначительными.

Однако оставлять столбцы nvarchar (max) в базе данных там, где они не нужны, довольно плохая форма. У него есть некоторые издержки производительности, и часто размеры данных весьма полезны для понимания таблицы данных - например, столбец varchar шириной 50 или 100 символов, вероятно, будет описанием или полем свободного текста, где (скажем) 10- 20 символов, вероятно, будут кодом. Вы будете удивлены, насколько много значат, что часто приходится делать из базы данных с помощью таких предположений.

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

ConcernedOfTunbridgeWells
источник
18

Хотя это не отвечает на ваш конкретный вопрос, это может помешать вам в первую очередь задавать вопрос: можно задать длину строковых переменных в классе модели C #, что заставит Entity Framework генерировать SQL, который использует фиксированный тип nvarchar (например nvarchar(50)) вместо nvarchar(max).

Например, вместо:

public string Name { get; set; }

Вы можете использовать:

[StringLength(50)]
public string Name { get; set; }

Вы также можете принудительно указать тип varcharвместо ( nvarcharпри желании) следующим образом:

[Column(TypeName = "VARCHAR")]
[StringLength(50)]
public string Name { get; set; }

Источник: /programming/7341783/entity-framework-data-annotations-set-stringlength-varchar/7341920

Джон Шнайдер
источник
2
Потребовалось найти этот ответ, чтобы я понял, что EF Core поддерживает настройку типа и длины одновременно ( varchar(50)), но EF 6 требует того, что содержится в этом ответе.
Синджай
9

Индексация самая большая проблема. От BOL:

Столбцы , которые имеют типов данных больших объектов (LOB) ntext, text, varchar(max), nvarchar(max), varbinary(max), xml, или imageне могут быть указаны в качестве ключевых столбцов для индекса.

Если вы не можете правильно индексировать, у вас будут медленные запросы. И с точки зрения целостности данных, наличие nvarchar(max)в поле большего количества неверных данных, чем указание предела.

HLGEM
источник
9

Да, поведение EF по умолчанию в отображении stringна nvarchar(max)не очень хорошее. В EF 6 вы можете добавить свое собственное пользовательское соглашение, чтобы переопределить это поведение с вашим собственным предпочтительным отображением по умолчанию.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<string>()
        .Configure(s => s.HasMaxLength(200).HasColumnType("varchar") );

    base.OnModelCreating(modelBuilder);
}

Переопределение, OnModelCreatingкак указано выше, изменит отображение по умолчанию для всех строк на varchar(200).

Павел
источник
1
Это не работает в EF Core 1.0
Shittu Joseph Olugbenga
the default EF behavior in mapping string to nvarchar(max) is not goodкажется, это ваше обобщенное мнение. Вы можете объяснить, почему это не хорошо? Или, как вы думаете, EF не является основой для бизнес-приложений, где вам нужно работать с несколькими языками? Потому что это желаемый тип столбца для работы с несколькими языками в базе данных.
Матиас Бургер
1
@MatthiasBurger nvarchar (max) ужасен для производительности, особенно в реплицируемой среде. Это не обобщенное мнение, это общеизвестный факт.
user2966445
@ user2966445 извините, я думаю, что было недоразумение :) конечно, maxэто ужасно. Но если вы хотите работать с несколькими языками (и их различными наборами символов), вам нужно использовать, nvarcharя не прав?
Матиас Бургер
@MatthiasBurger Правильно, используйте nvarchar для разных наборов символов, но весь этот пост посвящен производительности и длине полей, а не использованию nvarchar и varchar.
user2966445