gpt4 book ai didi

sql-server - UTF-8支持,SQL Server 2012和UTF8String UDT

转载 作者:行者123 更新时间:2023-12-05 01:10:12 25 4
gpt4 key购买 nike

通过研究针对我的特定应用程序的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表示的任何字符串。那是对的吗?此策略是否有缺点(例如,为每一行执行托管代码的性能成本,等等)?

最佳答案

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

如果您能够在磁盘空间上节省任何东西,那么这些收益将被整体性能上的损失所抵消。通过将UDT序列化为VARBINARY来存储它。因此,为了进行任何字符串比较或排序,在“二进制” /“普通”比较之外,您必须将所有其他值一个接一个地转换回UTF-8,然后再进行可以考虑的字符串比较语言差异。并且该转换将需要在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

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



在需要空间(磁盘,内存等)的地方,您有三个选择:


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


NCHAR(1 - 4000)NVARCHAR(1 - 4000)使用Standard Compression Scheme for Unicode,但仅从SQL Server 2008 R2开始,并且仅用于行内数据,而不用于溢出!这似乎比常规的ROW / PAGE压缩算法要好。
行内(不在LOB或OVERFLOW页中的行外)的NVARCHAR(MAX)XML(我猜也是VARBINARY(MAX)TEXTNTEXT)数据可以至少进行PAGE压缩,也许ROW压缩(不确定最后一个)。
任何行外数据,LOB或OVERLOW =无需压缩!

如果使用的版本早于2008,或者未在Enterprise Edition上使用,则可以具有两个字段:一个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)
);

如果您的字段只能包含适合扩展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语句将返回结果集,并且“ Generated”字段将正确显示字符。

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

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



更新2018-10-02

虽然这不是可行的选择,但SQL Server 2019在 VARCHAR / CHAR数据类型中引入了对UTF-8的本机支持。当前有太多的错误需要使用,但是,如果它们已修复,则在某些情况下是一种选择。请参阅我的文章“ Native UTF-8 Support in SQL Server 2019: Savior or False Prophet?”,以详细了解此新功能。

关于sql-server - UTF-8支持,SQL Server 2012和UTF8String UDT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8996002/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com