|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
简介Microsoft? SQL Server? 2000 包括各种支持国际化操作和环境的强大功能。扩展的多种语言功能使 SQL Server 2000 成为一种引人注目的数据库产品和应用程序平台。本文将完整地概述在全球范围内使用这些功能的方法。 除了列出一系列功能外,本文还将解释国际化/多种语言要求会怎样影响项目的各个方面。 什么是 Unicode?如何使用 Unicode?Unicode 支持是 SQL Server 2000 多种语言支持的基础。Unicode 是一种标准,旨在支持全球所有的脚本。无论是何种平台、程序还是语言,Unicode 为每个字符提供了一个唯一的代码数据点。支持 Unicode 的程序可以处理任何语言的数据。Unicode 3.0 能够处理多达 1,114,112 个字符。 Unicode 是由 Unicode Consortium 管理的行业标准。该组织认识到所有语言具有单一字符集的重要性。Microsoft 是 Unicode Consortium 的成员。大部分参加的公司与 Microsoft 都有相同的动机:在创建全球软件解决方案之际,呈现多种语言数据能力的重要性是显而易见的。其他许多公司和个人的加入是为了了解多种语言数据处理方面的问题和技巧。 现在的 Unicode Standard 3.01 版等同于 ISO-10646,后者是继 Unicode 1.1 发布之后与 Unicode 中所有代码数据点匹配的国际化标准。行业标准和国际化标准的有效结合后,可以防止任何个人因个人利益而违反这两种标准的目标:建立适用于所有人的字符集! 有关详细信息,请访问 Unicode Consortium 的 Web 站点。 编码Unicode 将代码数据点映射到字符,但实际上对数据在内存、数据库中或 Web 页上的表示方式并不作具体说明。这就是实际的 Unicode 数据编码的作用。Unicode 具有多种不同的编码。本节将说明以下几种常用的编码:
利用本文提供的有关编码的信息,您可以更好地了解 Unicode 以及存储 Unicode 的一些方法。通常情况下,只需选择一种 Unicode 数据类型即可,而不必考虑这些细节。但在下列情况下,了解编码都是相当重要的:
UCS-2UCS-2 是 Microsoft Windows NT? 4.0、Microsoft? SQL Server? 7.0 版和 Microsoft SQL Server 2000 所使用的主要 Unicode 编码。UCS-2 允许对 65,536 个不同代码点进行编码。存储在 SQL Server 2000 的 Unicode 中的所有信息均以这种编码进行存储,即无论所使用的是什么字符,都会用两个字节表示每一个字符。因此,拉丁字母“A”的处理方式与以下字母相同:
每个字母都有一个唯一的代码数据点(对于这些字母,代码数据点分别是 U+0041、U+0248、U+05DC、U+0BB1 和 U+3048,其中每个四位 16 进制数字都表示 UCS-2 所使用的两个字节)。 字节的排序在操作系统级中是至关重要的。由于 SQL Server 在 Windows 平台上运行,它使用的是 Little Endian 编码系统(指“小数在前”)。因此,象 0x1234 这样的 16 进制词将在内存中存储为 0x34 0x12。 UTF-16UTF-16 是 Microsoft Windows 2000 所使用的主要 Unicode 编码。即使在 Unicode 2.0 发布之前,人们都已清楚地认识到,仅用 65,536 个字符不能实现 Unicode 的目标(即支持每种语言中每个字符对应一个代码数据点)。对于有些语言(如中文),仅是对罕用字符进行编码,就需要这么多的字符。因此,人们添加了对代理范围的支持,以处理额外的 1,048,576 个字符。UTF-16 是完全支持对原始标准进行这种扩展的编码。有关代理范围的信息,请参见主题asp#intlfeaturesinsqlserver2000_whatrsurr">什么是代理? UTF-16 所遵循的是每个代码数据点两个字节的相同标准。但是,对于 UTF-16,某些代码数据点会使用紧跟其后的另一代码数据点来定义字符。 与 UCS-2 相似,UTF-16 也以 Little Endian 的方式进行存储,就象在默认情况下在 Windows 上存储一样。 重要 虽然 UCS-2 不识别代理,但它不会破坏代理所在数据库中的实际数据,而是将它们当作两个单独(未定义)的字符。 虽然 SQL Server 7.0 和 SQL Server 2000 可以毫无损失地存储代理对,但它们却将代理对当作两个未定义的 Unicode 字符,而不是一个单独的字符。这样的应用程序通常会被描述为代理“中立”或代理“安全”,其中安全是指能够存储数据,即使本身并不能与其进行交互。目前,由于没有正式定义的代理字符,所以代理“识别”应用程序相当少见。Microsoft Word 2000、Microsoft Windows 2000 和 Microsoft Internet Explorer 5.0 以及更高版本就是几种代理识别应用程序。 UTF-8许多要求 8 位编码的 ASCII 和其他面向字节的系统(如邮件服务器)都必须跨越多种使用不同编码、不同字节排序和不同语言的计算机。UTF-8 是一种与计算机上的字节排序无关的用于处理 Unicode 数据的编码架构。虽然 SQL Server 2000 不以 UTF-8 形式存储数据,但它在至少一种关键情形下支持 UTF-8,即支持可扩展标记语言 (XML)。有关详细信息,请参见本文后面的asp#intlfeaturesinsqlserver2000_topic16">使用 SQL Server 2000 的 XML 支持来处理多种语言数据。 其他许多数据库系统(如 Oracle 和 Sybase SQL Server)都支持使用 UTF-8 进行存储的 Unicode。根据服务器的实现方法,数据库引擎在技术上可以更为容易地实现这种支持(服务器上现有的所有文本管理代码每次只处理 1 字节的数据,因此不需要太大的更改)。在 Windows 环境中,UTF-8 存储具有以下缺点:
由于 XML 是较为重要的 Internet(它往往面向字节)通信标准,所以它默认为 UTF-8 是很有道理的。 什么是代理?代理区域是 Unicode 中从 U+D800 到 U+DFFF 的范围,它包含 1024 个低代理值和 1024 个高代理值。高代理和低代理可以进行组合,以提供对上百万个可能字符的访问。如果只有一个代理对的一半,则将被视为无效。要成为有效,必须始终有一个高代理和一个紧随其后的低代理。与检测 DBCS(双字节字符系统)字符所需的复杂规则相比较,这使代理检测变成了简单的范围检测。 当发布 SQL Server 7.0 时尚不存在任何代理。发布 SQL Server 2000 后,仅有的代理字符是那些与纯文本中的语言标记相关的字符。 重要 如上所述,代理可以在不导致任何数据丢失风险的情况下进行存储,但是,当尝试使用 SQL Server 字符串处理函数来处理数据时,应非常小心。另外,Windows 2000 目前只支持代理字符的代码数据点排序。 在发布 SQL Server 2000 后,经过 ISO 和 Unicode 标准组织的共同努力,更多的字符已添加到代理范围中,其中包括 40,000 个 CJKV(中文、日语、朝鲜语和越南语)象形文字。这些字符主要用于传统的和古典的文献,有助于对丰富的 CJKV 文学遗产进行编码。 SQL Server 2000 的数据类型很明显,数据库的核心任务是数据存储。本部分将讨论在使用 SQL Server 2000 数据类型存储国际化数据时出现的一些问题。 非 Unicode 文本类型:char、varchar 和 text当处理以 char、varchar 或 text 数据类型存储的文本数据时,需要考虑的最重要的限制是只能存储单个代码页中的信息。确切的代码页取决于列的排序规则(如果不存在列级排序规则,则使用数据库的排序规则)。要确定用于给定列的代码页,可以使用 COLLATIONPROPERTY 函数,如下例所示:
上例中添加了印地语,以指出许多区域设置(如格鲁吉亚语和印地语)都没有代码页,因为它们是“仅 Unicode”的排序规则。这些排序规则不适用于以上数据类型。 无论何时要将 Unicode 数据插入到这些列中,这些列都会使用 WideCharToMultiByte API 以及与排序规则相关联的代码页从 Unicode 进行内部转换。每当字符无法在给定代码页上显示时,它都将被替换为问号 (?);这样,不规范的问号就可以很恰当地指出因这种转换而被破坏的数据。另外,问号还会很恰当地指出您的确需要一个 Unicode 数据类型。如果您使用的是非 Unicode 类型的字符串字面量,则将首先使用数据库的默认代码页(从其排序规则派生)对其进行转换。 当代码页中并不包含您要支持的所有字符时,若要尝试存储数据,则可能遇到另一个问题。该问题的一个最好示例就是阿拉伯语脚本:它支持多种语言,包括伊朗语、柏柏尔语、波斯语、克什米尔语、哈萨克语、吉尔吉斯语、库尔德语、普什图语、信德语、Uighur 和乌尔都语等。以上所有语言都有作为 Windows 代码页 1256 基础的阿拉伯语所没有的附加字符。如果使用阿拉伯语排序规则在非 Unicode 列中存储这些额外的字符,这些字符将被转换为问号。之所以会产生这一问题,是因为在于多数情况下,Windows 会将某个特定代码页视作“最适合的”代码页。这意味着将无法保证您可以依赖该代码页来处理所有文本,不过它仍是最适合的可用代码页。 Unicode 文本类型:nchar、nvarchar 和 ntextSQL-92 规范定义了这些“N”(代表国家)数据类型,但没有特别要求将它们用于 Unicode,这些数据类型的实际定义将留待数据库平台或开发人员来处理。在 SQL Server 7.0 和 SQL Server 2000 中,这些数据类型的定义等同于 UCS-2/UTF-16 Unicode。务必要牢记,这是针对 Microsoft SQL Server 而言的。当您使用其他数据库服务器(如 Sybase SQL Server)时,务必要知道“N”数据类型并不特指 Unicode。 对于复杂脚本(如印地语和泰米尔语)的存储,务必要注意数据的顺序应该正确。许多种语言(如泰米尔语)实际上规定了某些字母在文本呈现时必须重新排序,从而使文本在内存中存储时的逻辑顺序不同于用户界面所显示的可视顺序。对于任何一种复杂的脚本语言(包括所有的印度语、阿拉伯语、波斯语、希伯来语以及其他许多种语言),数据都始终应该按照正确的逻辑顺序进行存储。这些数据的实际呈现是另外一个问题(请参见本文稍后的asp#intlfeaturesinsqlserver2000_topic8">用户界面中的多种语言数据)。 虽然“N”列确实支持任何语言或语言组合的数据,但只能以一种排序规则对这些数据进行实际排序(该问题的意义和影响将在asp#intlfeaturesinsqlserver2000_topic6">排序规则中进一步讨论)。本文先前所提及的代码页限制均不适用于 Unicode 列。 日期/时间类型:datetime 和 smalldatetime实际的数据类型没有实际的国际化含义;它们表示具有以下定义的日期/时间值: datetime 从公历 1753 年 1 月 1 日到公历 9999 年 12 月 31 日的日期和时间,精度为 1/300 秒(即 3.33 毫秒或 0.00333 秒)。 smalldatetime 从公历 1900 年 1 月 1 日到公历 2079 年 6 月 6 日的日期和时间,精度为分钟。29.998 秒或更小的 smalldatetime 值将下舍入到最接近的分钟数;而 29.999 秒或更大的值则上舍入至最接近的分钟数。 Microsoft SQL Server 不接受这些范围外的数据。实际数据在内部存储为两个整数(即 datetime 的 4 个字节整数和 smalldatetime 的 2 个字节整数),它们表示所讨论的日期和时间。由于实际值对于特定于区域设置的格式转换并没有任何实际的意义,所以将由开发人员按照需要来定义这种转换。 SQL Server 2000 支持多种不同的可在服务器上执行且特定于区域设置的转换,而不用依靠开发人员提供的定制解决方案。这些日期样式可以通过 CONVERT 函数来访问,该函数包括一种数据类型、一个表达式和一种可选样式,如下表所示。
以下示例说明了如何使用 CONVERT 函数:
然后,您可以按类似的方式将数据从字符串转换为日期值:
值得注意的是,当使用 Style 130(科威特语或 Hijri)转换这些日期时,如果排序规则不是一种使用 Unicode 转换代码页 1256 的阿拉伯排序规则,那么在转换为 char 数据类型时就可能会毁坏数据。下面的图解(图 1)说明了这一问题。 图 1:转换日期/时间的 Transact-SQL 注意,在 U.S. 客户端计算机上,尝试使用 char 数据类型会使阿拉伯字符转换为问号,并使 nchar 数据类型呈现为阿拉伯字符。由于 SQL Query Analyzer 内 SQL 网格的限制,这种特殊字符串仍然不能显示正确的格式(象在阿拉伯文客户端计算机上那样)。下面的图解(图 2)说明了实际的 Hijri 日期字符串应该如何显示。 图 2:Hijri 日期字符串 由于复杂脚本(如阿拉伯语)具有必须应用的成形规则,所以数据能够正确地呈现。在使用双向 (BIDI) 语言(如希伯来语)情况下,所有数据将被反转;其效果要比在使用阿拉伯语的情况下更为明显。这是因为字母的实际形状会根据周围的字母发生变化。Windows 2000 或支持阿拉伯语的 Windows 早期版本中不会出现这种问题。 另外,返回的数据字符串自身会在需要它的双向语言环境中引发问题,因为象 Internet Explorer 或 Windows 2000 这样的应用程序所使用的双向语言文本的布局规则会使日期以下面图解(图 3)中所示的形式显示。 图 3:双向日期字符串示例 此可视顺序 (dd hh:mi:ss yyyy mon :) 显然不是预期的顺序;虽然通过在字符串前添加相应的 Unicode 控制字符可以很容易解决该问题,但仍可以将该问题视作 CONVERT 函数中 130 样式的一般限制,如以下查询所示:
NCHAR 函数返回一个基于传入 Unicode 代码数据点的字符。8207 或 16 进制的 0x200F 是从右到左的标记 (RLM),有助于正确显示字符串。 性能和存储空间理想的情况下,每列是使用其中一种 Unicode 数据类型进行定义的。然而,当您不需要支持多种语言数据时,这样做会造成与存储空间和速度相关的问题。 存储空间问题Unicode 数据类型需要的实际空间量是每个字符两个字节,而非 Unicode 数据类型需要的空间量对于所有非 DBCS 文本而言是一个字节;对于使用 DBCS 的亚洲语言而言是两个字节。因此,如果您的数据不在某一亚洲代码页上,就要使用两倍的空间来存储数据。如果您要升级现有数据库或正在确定新项目的正确数据类型,就必须考虑这个问题。如果您只在单个(非亚洲语)代码页的某列中存储数据,就可以不使用 Unicode,以便节省磁盘上和内存中的空间。 速度问题速度问题相当复杂。以下是这些问题:
重要 要现实地评价性能问题,您必须通过测试来获得此情形下的真实数据。 系统表中的元数据信息SQL Server 2000 的系统表存储了它们包含为 Unicode 的所有数据。这样大大减少了因数据库和列的不同排序规则而产生的问题。目前还没有其他方法来解决同一服务器上的不同数据库既可以有 Unicode 列名也可以有非 Unicode 列名的问题。即使您此时只支持一种语言,SQL Server 也必须准备支持任何您今后可能要选择的语言。 当您从 SQL Server 6.5 或早期版本转换数据库和服务器时,很容易会为所转换的元数据而担心;其实,这种担心是不必要的。向 Unicode 的转换很简单,因为 SQL Server 的这些早期版本只使用在服务器级别上定义的一个代码页/排序规则。 其中一个重要问题是如何使用系统表中对象的标识符。SQL Server 2000 使用了 Unicode 2.0 字符属性定义来创建标识符中有效字符的列表(SQL Server 2000 的开发完成时,Unicode 3.0 尚未发布)。为了避免 Unicode 2.0 字符属性定义中未定义国际化字符的问题,您应该用中扩号 ([]) 或双引号 (") 来限定您的标识符。这样就可以阻止服务器检查有效的字符。 |