【问题标题】:UTF-8 Support, SQL Server 2012 and the UTF8String UDTUTF-8 支持、SQL Server 2012 和 UTF8String UDT
【发布时间】:2012-02-18 05:46:58
【问题描述】:

针对我的特定应用程序研究 SQL Server 的 VARCHAR 与 NVARCHAR 的优缺点后,我意识到如果 SQL Server 本身支持 UTF8 将是理想的。一些 SO 帖子表明它没有,例如:

Is VARCHAR like totally 1990s?

What are the main performance differences between varchar and nvarchar SQL Server data types?

然而,我在 SQL Server 2012 的 MSDN 文档中看到了这篇文章,其中展示了如何创建 UTF8String 用户定义的数据类型:

http://msdn.microsoft.com/en-us/library/ff877964(v=sql.110).aspx

似乎 UDT 将允许每个字符 8 位的空间(内存、磁盘)优势,同时足够灵活以存储可以用 UTF-8 表示的任何字符串。那是对的吗?这种策略是否有缺点(例如,为每一行执行托管代码的性能成本......)?

【问题讨论】:

    标签: sql-server unicode utf-8 sql-server-2012 user-defined-types


    【解决方案1】:

    通过 SQLCLR 创建自定义的用户定义类型不是,无论如何,它会让您替换任何本机类型。创建一些东西来处理专门的数据非常方便。但是字符串,即使是不同的编码,也远非专业化的。为您的字符串数据采用这条路线会破坏系统的任何可用性,更不用说性能,因为您将无法使用 任何 内置字符串函数。

    如果您能够在磁盘空间上节省任何东西,那么这些收益将被您在整体性能方面的损失所抵消。通过将 UDT 序列化为 VARBINARY 来存储 UDT。因此,为了进行 any 字符串比较或排序,在“二进制”/“序数”比较之外,您必须将所有其他值一一转换回 UTF-8 到 then进行可以解释语言差异的字符串比较。这种转换需要在 UDT 内完成。这意味着,与 XML 数据类型一样,您将创建 UDT 以保存特定值,然后公开该 UDT 的方法以接受字符串参数来进行比较(即Utf8String.Compare(alias.field1),或者,如果为输入,然后Utf8string1 = Utf8string2 并让= 运算符获取UTF-8 编码的字符串,然后执行CompareInfo.Compare())。

    除了上述注意事项之外,您还需要考虑通过 SQLCLR API 来回传递值是有代价的,尤其是在使用 NVARCHAR(MAX)VARBINARY(MAX) 而不是 NVARCHAR(1 - 4000)VARBINARY(1 - 4000) 时分别(请不要将此区别混淆为暗示使用SqlChars / SqlBytes vs SqlString / SqlBinary)。

    最后(至少在使用 UDT 方面),请不要忽略所查询的 UDT 是示例代码这一事实。唯一提到的测试纯粹是功能性的,与可伸缩性或“使用一年后的经验教训”无关。功能测试代码显示在下面的 CodePlex 页面中,在继续此决定之前应该先查看它,因为它可以让您了解您需要如何编写查询以便与之交互(这对于字段或两个,但对于大多数/所有字符串字段不是):

    http://msftengprodsamples.codeplex.com/SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql

    考虑到添加的持久计算列和索引的数量,是否真的节省了空间? ;-)


    如果需要考虑空间(磁盘、内存等),您有三个选择:

    1. 如果您使用的是 SQL Server 2008 或更高版本,并且使用的是企业版,那么您可以启用 Data Compression。数据压缩可以(但不会“总是”)压缩NCHARNVARCHAR 字段中的Unicode 数据。决定因素是:

      1. NCHAR(1 - 4000)NVARCHAR(1 - 4000) 使用 Standard Compression Scheme for Unicode,但仅从 SQL Server 2008 R2 开始,并且仅用于 IN ROW 数据,而不是 OVERFLOW!这似乎比常规的 ROW / PAGE 压缩算法要好。
      2. NVARCHAR(MAX)XML(我猜还有 VARBINARY(MAX)TEXTNTEXT)IN ROW 数据(不在 LOB 或 OVERFLOW 页面中的行外)至少可以进行 PAGE 压缩,并且 也许还有 ROW 压缩(不确定最后一个)。
      3. 任何 OFF ROW 数据、LOB 或 OVERLOW = 无需压缩!
    2. 如果在企业版上使用早于 2008 年的版本,您可以有两个字段:一个 VARCHAR 和一个 NVARCHAR。例如,假设您存储的 URL 大部分都是基本 ASCII 字符(值 0 - 127),因此适合 VARCHAR,但有时包含 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] 计算列中选择。对于插入和更新,您可以通过查看转换是否更改传入值来确定要使用的字段,该值必须是 NVARCHAR 类型:

      INSERT INTO TableName (..., URLa, URLu)
      VALUES (...,
              IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
              IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
             );
      
    3. 如果您的字段应该只包含适合扩展 ASCII 字符集的特定代码页的字符,那么只需使用 VARCHAR


    附:只是为了清楚起见:SQL Server 2012 中引入的新 _SC 排序规则只允许:

    • 正确处理补充字符/代理对的内置函数,以及
    • 用于排序和比较的补充字符的语言规则

    但是,即使没有新的 _SC 排序规则,您仍然可以将任何 Unicode 字符存储到 XML 或 N 前缀类型中,并在不丢失数据的情况下检索它。但是,当使用较旧的排序规则(即名称中没有版本号)时,所有补充字符都彼此等同。您需要使用_90_100 排序规则,它们至少可以让您进行二进制/代码点比较和排序;它们不能考虑语言规则,因为它们没有补充字符的特定映射(因此没有权重或规范化规则)。

    尝试以下方法:

    IF (N'?' = N'?') SELECT N'?' AS [TheLiteral], NCHAR(150150) AS [Generated];
    IF (N'?' = N'?') SELECT N'?' AS [TheLiteral], NCHAR(150151) AS [Generated];
    IF (N'?' COLLATE Tatar_90_CI_AI = N'?' COLLATE Tatar_90_CI_AI)
           SELECT N'? COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
    IF (N'?' = N'?') SELECT N'?';
    

    在默认排序规则以_SC 结尾的数据库中,只有第一个IF 语句将返回结果集,并且“生成”字段将正确显示字符。

    但是,如果数据库没有以 _SC 结尾的默认排序规则,并且排序规则不是 _90_100 系列排序规则,则前两个 IF 语句返回结果集,其中“ Generated”字段将返回NULL,“Literal”字段正确显示。

    对于 Unicode 数据,排序规则与物理存储无关。


    2018 年 10 月 2 日更新

    虽然这还不是一个可行的选项,但 SQL Server 2019 在 VARCHAR / CHAR 数据类型中引入了对 UTF-8 的原生支持。目前它有太多的错误无法使用,但如果它们被修复,那么这是 一些 场景的一个选项。有关此新功能的详细分析,请参阅我的帖子“Native UTF-8 Support in SQL Server 2019: Savior or False Prophet?”。

    【讨论】:

    • NVARCHAR(1 - 4000) 是什么意思?
    • @EricJ。这意味着选择一个介于 1 到 4000 之间的数字。
    • @EricJ。抱歉,如果我不清楚这一点。基本上就是 Aaron 所说的:这只是我表示非MAX NVARCHAR 类型的方式,它只能在 1 - 4000 的范围内。
    猜你喜欢
    • 2015-08-09
    • 2010-10-05
    • 2021-08-01
    • 2014-03-21
    • 2018-08-07
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多