EF Code First对所有字符串使用nvarchar(max)。这会损害查询性能吗?


29

我有一些使用“实体框架代码优先”创建的数据库;应用程序正常运行,总的来说,我对Code First的功能感到非常满意。根据需要,我首先是一名程序员,然后是DBA。我正在阅读有关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个字符。我希望此表的开头很小(<100k行),但随着时间的推移会显着增长(> 1m行)。显然,消息可能大小不一,可能不会被查询。

我想知道,是否将我的“名称”和“源”列定义为nvarchar(max)当我从未期望它们大于150个字符时对性能产生影响?


5
看起来您需要应用[MaxLength][StringLength]属性。@PaulWhite的答案在此处提到了
Martin Smith,

3
是的varchar(max)随处使用都会损害您的表现 -请勿这样做!使用适当的数据类型- varchar(max) 确实需要超过8000个字符时才使用!(我从未见过这么长的人的名字或电子邮件!)-请参见再使用VARCHAR(n)有什么意义?有关更多信息
marc_s 2013年

@marc_s很棒的链接。我知道它确实会影响性能。当我用SQL定义自己的表时,我使用varchar(n)。我的问题更多是关于它在多大程度上损害了性能(尽管我意识到,目前还不清楚。)
2013年

Answers:


24

较大的nvarchar(最大)数据项(超过8000个字节左右)将溢出到文本存储中,并需要其他I / O。较小的项目将存储在行中。有控制此行为的选项- 有关更多详细信息,请参见此MSDN文章

如果存储在行中,则不会有明显的I / O性能开销;在处理数据类型时可能会有额外的CPU开销,但这可能很小。

但是,将nvarchar(max)列留在不需要它们的数据库周围是很差的形式。它确实有一些性能开销,通常数据大小对于理解数据表非常有帮助-例如,一个50或100个字符宽的varchar列很可能是描述或自由文本字段,其中(例如)10- 20个字符可能是一个代码。您会惊讶于通过这样的假设人们常常必须从数据库中推断出多少含义。

在数据仓库中(不经常在支持不佳或未提供文档的遗留系统上工作),具有易于理解的数据库架构非常有价值。如果您认为数据库是应用程序的旧版,请尝试与那些要从您那里继承数据库的人保持友好。


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; }

资料来源:https : //stackoverflow.com/questions/7341783/entity-framework-data-annotations-set-stringlength-varchar/7341920


2
找到这个答案是为了让我弄清楚EF Core支持同时设置类型和长度(varchar(50)),但是EF 6需要此答案中的内容。
Sinjai

9

索引最大的问题。从BOL:

列,其大对象(LOB)的数据类型ntexttextvarchar(max)nvarchar(max)varbinary(max)xml,或image不能被指定为索引键列。

如果无法正确建立索引,则查询速度会很慢。并且从数据完整性的角度来看,nvarchar(max)与指定限制相比,具有允许将更多的坏数据放入字段中。


9

是的,映射string到中的默认EF行为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 '16

the default EF behavior in mapping string to nvarchar(max) is not good这似乎是您的普遍看法。你能解释为什么这不好吗?或者,您认为EF不是需要使用多种语言的业务应用程序框架?因为那是处理数据库上多种语言所需的列类型。
Matthias Burger

1
@MatthiasBurger nvarchar(max)的性能令人恐惧,尤其是在复制环境中。这不是一个普遍的观点,而是众所周知的事实。
user2966445

@ user2966445对不起,我认为这是一个误会:)当然,max这太可怕了。但是,如果您想使用多种语言(以及它们的不同字符集),则需要使用,nvarchar我错了吗?
马提亚斯·伯格

@MatthiasBurger是的,对不同的字符集使用nvarchar,但是整个文章都是关于性能和字段长度的,而不是使用nvarchar vs. varchar。
user2966445
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.