在最终向用户呈现结果集之前,我对表变量做了很多工作。例如,我可能从许多不同的表中拉入一大堆列,如下所示:
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(n)
,但它在某些环境中存在可靠性和性能风险。如果你认为这应该被删除那么公平(但请停止争论我欣赏所有输入!)
答案 0 :(得分:10)
我无法想到表变量中的nvarchar(max)会有任何与在表(the downsides of which are explained in this question)中使用nvarchar(max)不同的陷阱,除了陷阱是由于表变量和临时/永久表之间的差异(例如,可怕的统计数据,没有二级索引等)。 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。部分相关片段,我的拼写/语法更正:
因此,如果您确定nvarchar列的长度小于8000,则不要将列定义为nvarchar(max),而是尽可能将其定义为nvarchar(fixedlength)。我看到使用固定长度的主要优点是:
内存授权可能是服务器已经缺乏内存的一个大问题。正如预期的行大小更多,优化器将估计更多的内存授予,这个值将远远高于实际需要,这将浪费像内存一样宝贵的资源。如果您有几个使用nvarchar(max)列的查询并且需要排序,则服务器可能存在与内存相关的问题。这可能是一个很大的问题。
他列出的其他优势与索引有关。无论如何,表变量都不是问题,因为您无法创建二级索引(在SQL Server 2014之前)。
但是再一次,无论你从哪个类型的表结构中提取数据,这个潜在的问题都没有什么不同 - 临时表,表变量,永久表等。