6

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

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

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

顺着 UCS-2 流向上游泳可能会遇到什么问题?

4

2 回答 2

13

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

与其他一些允许选择编码的 RDBMS 不同,SQL Server仅以UTF-16(Little Endian)存储 Unicode 数据,而对于任何代码页,非 Unicode 数据以 8 位编码(扩展 ASCII、DBCS 或 EBCDIC)存储由字段的排序规则暗示。

微软选择 UCS-2 的原因我不完全理解

鉴于 UTF-16 于 1996 年中期引入并在 2000 年完全指定,他们选择UCS-2 的决定是有道理的。许多其他系统也使用(或使用)它(请参阅:https://en. wikipedia.org/wiki/UTF-16#Usage)。他们继续使用它的决定可能更值得怀疑,尽管这可能是由于 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(即补充字符)结尾。

Wikipedia ...指出 UCS-2 已过时,取而代之的是 UTF-16

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

Wikipedia ...指出 UTF-8 是一种可变宽度字符集,能够编码任何 Unicode 数据点

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

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

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

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

同样,这是真的,但完全不相关,因为 UTF-16 和 UTF-32 也映射所有 Unicode 代码点。

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

视情况而定,这很可能是真的,您担心这种浪费的使用是正确的。但是,正如我在导致这个问题(UTF-8 支持、SQL Server 2012 和 UTF8String UDTVARCHAR )的问题中提到的那样,如果大多数行都可以满足但有些需要,您有一​​些选项可以减少浪费的空间量是NVARCHAR。最好的选择是启用 ROW COMPRESSION 或 PAGE COMPRESSION(仅限企业版!)。从 SQL Server 2008 R2 开始,它们允许非 MAXNVARCHAR字段使用“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 在VARCHAR/CHAR数据类型中引入了对 UTF-8 的本机支持。目前它有太多的错误无法使用,但如果它们被修复,那么这是某些场景的一个选项。请参阅我的帖子“ SQL Server 2019 中的 Native UTF-8 Support: Savior or False Prophet? ”,详细分析这个新特性。

于 2015-09-30T06:50:03.400 回答
0

您所说的“顺着 UCS-2 流”是什么意思?

以下是您的选择:

不推荐但可能:

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

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

于 2012-01-25T20:11:27.527 回答