【问题标题】:nvarchar(max) versus nvarchar(n) in table variable columns表变量列中的 nvarchar(max) 与 nvarchar(n)
【发布时间】:2014-01-15 15:32:54
【问题描述】:

在最终将结果集呈现给用户之前,我对表变量做了大量工作。例如,我可能会从许多不同的表中提取大量列,如下所示:

DECLARE @tmp TABLE
(
ID int,
username nvarchar(50),  -- data taken from tbl_Users
site nvarchar(50),      -- data taken from tbl_Sites
region nvarchar(100),   -- data taken from tbl_Regions
currency nvarchar(5)    -- data taken from tbl_Currencies
)

我花了很多时间查看对象资源管理器以确保列的数据长度正确(与原始表匹配)。有时,如果我更改表架构但不更新所有过程,我可能会遇到截断错误。

采取懒惰的方法并这样做有什么问题:

DECLARE @tmp TABLE
(
ID int,
username nvarchar(max),
site nvarchar(max),
region nvarchar(max),
currency nvarchar(max)
)

nvarchar(max) 是否真的用尽了更多的内存,或者这是根据数据大小分配的内存?还有其他陷阱吗?

请注意,我知道第三方工具可以跳转到定义,但这不是我要问的。

更新

重复的问题有价值,但问题不完全相同恕我直言。副本围绕实际表格的设计,而不是表格变量。但是,答案有一些优点,即:

  • nvarchar(max) 与 nvarchar(8000) 在 8000+ 数据长度之前在资源使用方面没有区别
  • 业务逻辑层依赖于结构和有意义数据,因此指定与原始数据互补的列大小会提供价值

从这个意义上说,在表变量中使用nvarchar(max) 而不是nvarchar(n) 似乎很好,但在某些 环境中它存在可靠性和性能风险。如果您认为这应该被删除,那么就足够公平了(但请不要争论我感谢所有的意见!)

【问题讨论】:

  • 这是用户定义类型应该解决的问题,但鉴于您无法在定义后重新定义类型,因此在可能发生重新定义的模式中使用它们会很痛苦,而您想要保留数据(如果它们确实有效,您将能够在两个表中都有username 类型的username,并且类型定义将定义基本类型(varchar),长度(50 )等)
  • 我也使用(最大)快捷方式。我认为唯一的问题是您可以将更多的文本连接到变量中,而不是最终放入列中。 imo不是一个大问题。
  • 您通常在这些表变量中处理多少行?如果数量很少,请将您的优化工作集中在其他地方,恕我直言。如果数量很大,请测试。
  • 行数是一个重要的决定因素,正如 Aaron 指出的那样。如果您要处理的行数超过少量(小可能是 10-100 之间的任何地方),您最好查看临时表而不是变量。除了插入最终目的地时数据长度不匹配的问题之外,整个问题可能没有实际意义。
  • 谁清理了所有的争论?!?

标签: sql-server tsql sql-server-2012


【解决方案1】:

除了由于首先表变量和临时/永久表之间的差异(例如糟糕的统计数据,没有二级索引等)。 Martin Smith draws a great comparison between table variables and temp tables here.

您仍然需要担心某些问题,例如,如果您使用的是经典 ASP/ADO 等古老技术,您可能会发现必须最后列出 MAX 列以确保结果准确。 I explained this here back in 2000, before MAX types were introduced;但他们在那些旧提供程序中存在与TEXT/NTEXT 相同的问题。您极不可能使用该技术,但我想我会提到它以防万一。

不过,我建议您在编写代码时直接接受并编写正确的类型。它们很容易从元数据中派生出来(例如sys.columns 或右键单击表格并说脚本为 > 创建到 > 剪贴板),这样做可以防止任何问题(例如 the one @JC. mentioned above 关于长度不匹配的问题,可能导致溢出/截断)。

另外,正如我之前所暗示的,如果您有大量的行(感谢@Stuart),您应该考虑使用#temp 表。我仍然认为无论您选择什么都应该定义明确。在这种情况下,对所有事情都使用 MAX 的唯一好处是它可以让你变得懒惰,同时让你面临很大的风险。您编写一次代码,但您的用户运行它无数次。多花几分钟时间让您的数据类型正确,即使这意味着如果架构发生更改,您必须在以后更正两次。

至于nvarchar(max) 的内存使用情况,是的,这可能会改变你的表现。 See this blog post for some evidence。部分相关的 sn-p,以及我的拼写/语法更正:

因此,如果您确定您的 nvarchar 列的长度将小于 8000,则不要将该列定义为 nvarchar(max),而是尽可能将其定义为 nvarchar(fixedlength)。我看到使用固定长度的主要优点是:

在服务器内存不足的情况下,内存授予可能是一个大问题。由于预期的行大小更大,优化器将估计更多的内存授予,这个值将比实际需要的高得多,这将浪费像内存一样宝贵的资源。如果您有几个使用 nvarchar(max) 列的查询并且需要排序,则服务器可能存在与内存相关的问题。这可能是一个很大的性能问题。

他列出的其他优势与索引有关。无论如何,表变量都不是问题,因为您无法创建二级索引(在 SQL Server 2014 之前)。

但再一次强调,无论您从哪种类型的表结构中提取数据——临时表、表变量、永久表等,这个潜在的问题实际上并没有什么不同。

【讨论】:

  • 这种类型的答案是 SO 如此出色的原因。绝对惊艳。谢谢。
猜你喜欢
  • 2013-12-12
  • 2011-01-09
  • 2019-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
相关资源
最近更新 更多