尽管 研究选择 为了将大部分是英语但有时不是的数据存储在可能非常大的 SQL Server 数据库中,我倾向于将大多数字符串数据存储为 UTF-8 编码。

然而,微软选择 UCS-2 的原因我并不完全理解,这让我对这种倾向产生了怀疑。SQL Server 2012 的文档确实展示了如何创建 UTF-8 UDT, ,但 UCS-2 的决定可能遍及 SQL Server。

维基百科 (有趣的是,UCS-2 已过时,取而代之的是 UTF-16)指出 UTF-8 是一种可变宽度字符集,能够对任何 Unicode 数据点进行编码,并且它 provides the de facto standard encoding for interchange of Unicode text. 。因此,感觉任何 Unicode 字符都可以用 UTF-8 表示,并且由于大多数文本都是英语,因此表示形式将比 UCS-2 紧凑两倍(我知道磁盘“便宜”,但磁盘缓存并不不是,并且内存与我正在处理的数据大小不相比较。当工作集大于可用 RAM 时,许多操作会呈指数级下降。

在 UCS-2 流中游泳可能会遇到哪些问题?

有帮助吗?

解决方案

由于将大部分是英语但有时不是的数据存储在可能非常大的 SQL Server 数据库中,我倾向于将大多数字符串数据存储为 UTF-8 编码。

与其他允许选择编码的 RDBMS 不同,SQL Server 存储 Unicode 数据 仅有的 UTF-16(Little Endian)格式的数据,以及字段排序规则隐含的任何代码页的 8 位编码(扩展 ASCII、DBCS 或 EBCDIC)中的非 Unicode 数据。

微软选择UCS-2的原因我不太明白

他们的决定 选择 鉴于 UTF-16 于 1996 年中期引入并于 2000 年全面规范,UCS-2 就足够有意义了。许多其他系统也使用(或使用过)它(请参阅: https://en.wikipedia.org/wiki/UTF-16#用法)。他们的决定 继续 尽管这可能是由于 Windows 和 .NET 是 UTF-16,但它可能会更值得怀疑。UCS-2 和 UTF-16 之间的字节物理布局相同,因此从 UCS-2 升级系统以支持 UTF-16 应该是纯功能性的,无需更改任何现有数据。

SQL Server 2012 的文档确实显示了如何创建 UTF-8 UDT,

不。通过 SQLCLR 创建自定义用户定义类型是 不是, ,以任何方式,将为您提供任何本机类型的替代品。它对于创建处理专门数据的东西非常方便。但字符串,即使是不同的编码,也远非专业化。对字符串数据采用这种方法会破坏系统的任何可用性,更不用说性能,因为您将无法使用 任何 内置字符串函数。如果您能够节省磁盘空间上的任何内容,那么您所损失的整体性能就会抹去这些收益。存储 UDT 是通过将其序列化为 VARBINARY. 。所以为了做到 任何 字符串比较或排序,除了“二进制”/“序数”比较之外,您必须将所有其他值一一转换回 UTF-8,然后进行可以考虑语言差异的字符串比较。

另外,该“文档”实际上只是示例代码/概念证明。该代码编写于 2003 年( http://msftengprodsamples.codeplex.com/SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/CS/UTF8String/Utf8String.cs )对于 SQL Server 2005。我看到了一个测试功能的脚本,但没有涉及性能。

但 UCS-2 的决定可能会影响到 SQL Server。

是的,非常如此。默认情况下,内置函数的处理仅适用于 UCS-2。但从 SQL Server 2012 开始,您可以通过使用以下排序规则之一让它们处理完整的 UTF-16 字符集(从 Unicode 版本 5 或 6 开始,具体取决于您的操作系统和 .NET Framework 版本)名字结尾为 _SC (IE。补充字符)。

维基百科...注意到 UCS-2 已过时,取而代之的是 UTF-16

正确的。UTF-16 和 UCS-2 都使用 2 字节代码点。但 UTF-16 成对使用其中一些(即代理对)来映射附加字符。用于这些对的码点在 UCS-2 中为此目的而保留,因此不用于映射到任何可用符号。这就是为什么您可以在 SQL Server 中存储任何 Unicode 字符,并且可以正确存储和检索该字符。

维基百科...请注意,UTF-8 是一种可变宽度字符集,能够对任何 Unicode 数据点进行编码

正确,尽管有误导性。是的,UTF-8 是可变宽度的,但 UTF-16 的可变宽度也很小,因为所有补充字符均由两个双字节代码点组成。因此,UTF-16 每个符号使用 2 或 4 个字节,但 UCS-2 始终为 2 个字节。但这不是误导性的部分。具有误导性的是,任何其他 Unicode 编码都无法对所有其他代码点进行编码。虽然 UCS-2 可以保存它们但不能解释它们,但 UTF-16 和 UTF-32 都可以映射所有 Unicode 代码点,就像 UTF-8 一样。

并且它[编辑:UTF-8] 提供了用于 Unicode 文本交换的事实上的标准编码。

这可能是真的,但从操作角度来看,这完全无关紧要。

感觉任何Unicode字符都可以用UTF-8表示

同样,确实如此,但完全不相关,因为 UTF-16 和 UTF-32 也映射所有 Unicode 代码点。

由于大多数文本都是英文,因此其表示形式几乎是 UCS-2 的两倍

根据具体情况,这很可能是真的,您对这种浪费的使用感到担忧是正确的。然而,正如我在导致这个问题的问题中提到的( UTF-8 支持、SQL Server 2012 和 UTF8String UDT ),如果大多数行都可以容纳,您有几个选项可以减少浪费的空间量 VARCHAR 但有些需要 NVARCHAR. 。最好的选择是启用行压缩或页压缩(仅限企业版!)。从 SQL Server 2008 R2 开始,它们允许非 MAX NVARCHAR 字段使用“Unicode 标准压缩方案”,它至少与 UTF-8 一样好,在某些情况下甚至比 UTF-8 更好。 NVARCHAR(MAX) 字段不能使用这种奇特的压缩, ,但它们的 IN ROW 数据可以受益于常规 ROW 和/或 PAGE 压缩。请参阅以下内容,了解此压缩的说明以及比较数据大小的图表:原始 UCS-2 / UTF-16、UTF-8 和启用数据压缩的 UCS-2 / UTF-16。

SQL Server 2008 R2 - UCS2 压缩是什么 - 对 SAP 系统的影响

另请参阅 MSDN 页面 数据压缩 了解更多详细信息,因为有一些限制(除了仅在企业版中可用之外 - 但可用于 全部 从 SQL Server 2016 SP1 开始的版本!!)以及压缩可能会使情况变得更糟的某些情况。

我知道磁盘“便宜”

该说法的准确性取决于人们如何定义“磁盘”。如果您指的是可以在商店购买现成的用于台式机/笔记本电脑的商品零件,那么当然可以。但是,如果就将用于您的生产系统的企业级存储而言,那么请有趣地向控制预算的人解释他们不应该拒绝您想要的价值数百万美元以上的 SAN,因为它“便宜” “;-)。

在 UCS-2 流中游泳可能会遇到哪些问题?

我想不到。好吧,只要您不遵循任何可怕的建议来执行诸如实现 UDT 或将所有字符串转换为 VARBINARY, ,或使用 NVARCHAR(MAX) 对于所有字符串字段;-)。但在您可能担心的所有事情中,使用 UCS-2 / UTF-16 的 SQL Server 不应该是其中之一。

但是,如果由于某种原因,不支持 UTF-8 的问题非常重要,那么您可能需要找到另一个允许 UTF-8 的 RDBMS 来使用。


更新2018-10-02

虽然这还不是一个可行的选择,但 SQL Server 2019 在以下版本中引入了对 UTF-8 的本机支持: VARCHAR / CHAR 数据类型。目前它有太多的错误,无法使用,但如果它们被修复,那么这是一个选项 一些 场景。请看我的帖子“SQL Server 2019 中的本机 UTF-8 支持:救世主还是假先知?”,详细分析这一新功能。

其他提示

“沿着 UCS-2 流向上游”是什么意思?

以下是您的选择:

不推荐但可能:

  • 实施 UDT。这将是一项繁重的工作,并且您将失去收费支持(OR 映射,当然还有一些适用于本机类型的 SQL Server 功能)。
  • 使用 varbinary(max):需要您进行自定义转换代码。无范围索引。
  • 使用 nvarchar(N) 并打开行压缩。从 SQL Server 2008 R2 开始,这将使用与 UTF-8 一样紧凑的编码。但这需要企业版。

请参阅评论以了解这些方法的严重缺点。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top