虽然已经有不少答案了,但我还是要说几点,因为有些问题并没有得到解决,或者没有清楚地表达。
首先:不要总是使用NVARCHAR。这是一种非常危险、而且经常很昂贵的态度和方法。同样也不应该说“从不使用游标”,因为它们有时是解决特定问题最有效的手段,而且常见的用WHILE
循环代替游标的方法通常比正确地实现一个游标更慢。
你唯一能使用“始终”这个词的时候是建议“始终做最适合情况的事情”。当你试图在短期开发时间(经理:“我们需要这个功能——你直到刚才才知道——一周前!”)与长期维护成本(最初迫使团队在3周之内完成3个月项目的经理:“为什么我们会遇到这些性能问题?我们怎么可能做出没有灵活性的X?我们不能承受几周的停顿去修复这个问题。我们本周能做些什么来回到我们的优先事项?我们肯定需要花更多时间进行设计,以免这种情况持续发生!”)之间取得平衡时,这可能很难确定。
其次:@gbn的答案涉及到在某些数据建模决策上考虑的一些重要问题。但还有更多需要考虑的因素:
- 事务日志文件的大小
- 复制所需的时间(如果使用复制)
- ETL所需的时间(如果正在进行ETL)
- 将日志发送到远程系统并恢复所需的时间(如果使用日志传送)
- 备份的大小
- 完成备份所需的时间
- 执行还原所需的时间(这可能在某天很重要)
- 临时数据库所需的大小
- 触发器的性能(对于存储在tempdb中的插入和删除表)
- 行版本的性能(如果使用SNAPSHOT隔离,因为版本存储在tempdb中)
- 当首席财务官说他们去年刚花了100万美元购买SAN,所以不会授权另外250k用于增加存储空间时,获得新磁盘空间的能力
- 执行INSERT和UPDATE操作所需的时间
- 执行索引维护所需的时间
- 等等,等等。
浪费空间对整个系统有巨大的连锁影响。我写了一篇详细介绍这个问题的文章:
Disk Is Cheap! ORLY?(需要免费注册;抱歉我无法控制该政策)。
第三点:尽管一些答案错误地关注了“这是一个小应用程序”的方面,而一些答案正确地建议“使用适当的内容”,但是没有一个答案为O.P.提供了真正的指导。在问题中提到了一个重要细节,即这是他们学校的网页。很好!因此我们可以建议:
- 学生和/或教职员工姓名字段可能应该是如果你正在使用SQL Server 2008 - 2016 RTM的企业版,或者在使用SQL Server 2016 SP1(该版本在所有版本中提供了数据压缩功能)或更高版本,则可以启用数据压缩。数据压缩可以(但不总是)压缩
NCHAR
和NVARCHAR
字段中的Unicode数据。影响因素如下:
NCHAR(1 - 4000)
和NVARCHAR(1 - 4000)
使用标准的Unicode压缩方案,但仅支持从SQL Server 2008 R2开始,并且仅适用于行内数据,而不是溢出数据!这似乎比常规的ROW / PAGE压缩算法更好。
NVARCHAR(MAX)
和XML
(我猜也包括VARBINARY(MAX)
、TEXT
和NTEXT
)的行内数据可以至少进行PAGE压缩,但不能进行ROW压缩。当然,PAGE压缩取决于行内值的大小:我测试了VARCHAR(MAX),发现6000个字符/字节的行无法压缩,但4000个字符/字节的行可以。
任何溢出数据,LOB或OVERLOW = 没有压缩!
如果使用SQL Server 2005或2008 - 2016 RTM且不使用企业版,则可以有两个字段:一个VARCHAR
和一个NVARCHAR
。例如,假设您正在存储大多数都是基本ASCII字符(值为0 - 127)的URL,并且有时具有Unicode字符。您的模式可以包括以下3个字段:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
在这个模型中,你仅从计算列[URL]
中进行SELECT。对于插入和更新操作,需要确定使用哪个字段,方法是看转换是否会更改传入的值,而这个值必须是NVARCHAR
类型:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
你可以将传入的值压缩成
VARBINARY(MAX)
,然后在输出时解压缩:
- 对于 SQL Server 2005 - 2014: 可以使用 SQLCLR。免费版本的SQL#(我编写的 SQLCLR 库)带有 Util_GZip 和 Util_GUnzip
- 对于 SQL Server 2016 及更新版本:可以使用内置的
COMPRESS
和 DECOMPRESS
函数,它们也是 GZip。
如果使用的是 SQL Server 2017 或更新版本,则可以考虑将表制作为聚集列存储索引。
尽管这还不是一个可行的选择,但 SQL Server 2019 引入了对
VARCHAR
/
CHAR
数据类型中 UTF-8 的本机支持。目前存在太多缺陷使其无法使用,但如果修复了这些缺陷,则这是一些情况下的选项。请参阅我的帖子“
SQL Server 2019 中的本机 UTF-8 支持:救世主还是伪先知?”,详细分析了这个新功能。
NVARCHAR
”,这样做可能对性能和硬件成本/预算产生非常负面的影响。少数行,甚至几千行都没有关系,但系统增长速度比人们预期的更快,所以目前接受的答案是对社区的不利影响。谢谢。 - Solomon Rutzky