排序规则和代码页

In-Memory OLTP 对内存优化表中 (var)char 字符列支持的代码页,以及索引和原生编译存储过程中使用的排序规则,有一定的限制。

字符值的代码页确定字符与存储在表中的字节表示形式的映射。 例如,使用 Windows Latin 1 代码页(1252;SQL Server 默认值),字符“a”对应于字节0x61。

与(var)char值关联的排序规则决定其字符编码页。 例如,排序规则 SQL_Latin1_General_CP1_CI_AS 具有关联的代码页 1252。

值的排序规则是从数据库排序规则继承的,也可以使用 COLLATE 关键字显式指定。 如果数据库包含内存优化表或本机编译的存储过程,则无法更改数据库排序规则。 以下示例设置数据库排序规则并创建一个具有不同排序规则的列的表。 数据库使用拉丁文不区分大小写的排序规则。

仅当索引使用 BIN2 排序规则时,才能对字符串列创建索引。 LastName 变量使用 BIN2 排序规则。 FirstName 使用数据库默认值,即CI_AS(大小写不敏感、重音敏感)。

重要

不能对不使用 BIN2 排序规则的索引字符串列使用 order by 或 group by。

CREATE DATABASE IMOLTP  
  
ALTER DATABASE IMOLTP ADD FILEGROUP IMOLTP_mod CONTAINS MEMORY_OPTIMIZED_DATA  
ALTER DATABASE IMOLTP ADD FILE( NAME = 'IMOLTP_mod' , FILENAME = 'c:\data\IMOLTP_mod') TO FILEGROUP IMOLTP_mod;  
--GO  
  
--  set the database collations  
ALTER DATABASE IMOLTP COLLATE Latin1_General_100_CI_AS  
GO  
  
--  
USE IMOLTP   
GO  
  
-- create a table with collation  
CREATE TABLE Employees (  
  EmployeeID int NOT NULL ,   
  LastName nvarchar(20) COLLATE Latin1_General_100_BIN2 NOT NULL INDEX IX_LastName NONCLUSTERED,   
  FirstName nvarchar(10) NOT NULL ,  
  CONSTRAINT PK_Employees PRIMARY KEY NONCLUSTERED HASH(EmployeeID)  WITH (BUCKET_COUNT=1024)  
) WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_AND_DATA)  
GO  

以下限制适用于内存优化表和本机编译的存储过程:

  • 内存优化表中的 varchar 列必须使用代码页 1252 的排序规则。 此限制不适用于 n(var)char 列。 以下代码检索所有 1252 种排序规则:

    -- all supported collations for (var)char columns in memory-optimized tables  
    select * from sys.fn_helpcollations()  
    where collationproperty(name, 'codepage') = 1252;  
    

    如果需要存储非拉丁字符,请使用 n(var)char 列。

  • 只能使用 BIN2 排序规则指定 (n)(var)char 列上的索引(请参阅第一个示例)。 以下查询检索所有支持的 BIN2 排序规则:

    -- all supported collations for indexes on memory-optimized tables and   
    -- comparison/sorting in natively compiled stored procedures  
    select * from sys.fn_helpcollations() where name like '%BIN2'  
    

    如果通过解释的 Transact-SQL 访问表,则可以使用 COLLATE 关键字通过表达式或排序操作更改排序规则。 有关此示例,请参阅最后一个示例。

  • 如果数据库排序规则不是代码页 1252 排序规则,则本机编译的存储过程不能使用 (var)char 类型的参数、局部变量或字符串常量。

  • 本机编译存储过程中的所有表达式和排序操作都必须使用 BIN2 排序规则。 这意味着所有比较和排序作都基于字符的 Unicode 码位(二进制表示形式)。 例如,所有排序都区分大小写(“Z”位于“a”之前)。 如有必要,请使用 Transact-SQL 指令进行不区分大小写的排序和比较。

  • 本机编译的存储过程不支持截断 UTF-16 数据。 这意味着,如果排序规则具有_SC属性,则 n(var)char(n) 值不能转换为类型 n(var)char(i), 如果 i<n。 例如,不支持以下各项:

    -- column definition using an _SC collation  
     c2 nvarchar(200) collate Latin1_General_100_CS_AS_SC not null   
    -- assignment to a smaller variable, requiring truncation  
     declare @c2 nvarchar(100) = '';  
     select @c2 = c2  
    

    本机编译的存储过程不支持包含 UTF-16 数据的字符串作函数,例如 LEN、SUBSTRING、LTRIM 和 RTRIM。 不能将这些字符串操作函数用于具有_SC排序规则的 n(var)char 值。

    使用足够大的类型声明变量,以避免截断。

以下示例显示了 In-Memory OLTP 中排序规则限制的一些影响和解决方法。 此示例使用上面指定的 Employees 表。 此示例列出所有员工。 请注意,对于 LastName,由于二进制排序规则,大写名称在小写之前排序。 因此,“Thomas”位于“nolan”之前,因为大写字符的代码点较低。 FirstName 具有不区分大小写的排序规则。 因此,排序按字母顺序排序,而不是字符的代码点。

-- insert a number of values  
INSERT Employees VALUES (1,'thomas', 'john')  
INSERT Employees VALUES (2,'Thomas', 'rupert')  
INSERT Employees VALUES (3,'Thomas', 'Jack')  
INSERT Employees VALUES (4,'Thomas', 'annie')  
INSERT Employees VALUES (5,'nolan', 'John')  
GO  
  
-- ===========  
SELECT EmployeeID, LastName, FirstName FROM Employees  
ORDER BY LastName, FirstName  
GO  
  
-- ===========  
-- specify collation: sorting uses case-insensitive collation, thus 'nolan' comes before 'Thomas'  
SELECT * FROM Employees  
ORDER BY LastName COLLATE Latin1_General_100_CI_AS, FirstName  
GO  
  
-- ===========  
-- retrieve employee by Name  
-- must use BIN2 collation for comparison in natively compiled stored procedures  
CREATE PROCEDURE usp_EmployeeByName @LastName nvarchar(20), @FirstName nvarchar(10)  
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER  
AS BEGIN ATOMIC WITH   
(  TRANSACTION ISOLATION LEVEL = SNAPSHOT,  
  LANGUAGE = N'us_english'  
)  
  SELECT EmployeeID, LastName, FirstName FROM dbo.Employees  
  WHERE   
    LastName = @LastName AND  
    FirstName COLLATE Latin1_General_100_BIN2 = @FirstName  
  
END  
GO  
  
-- this does not return any rows, as EmployeeID 1 has first name 'john', which is not equal to 'John' in a binary collation  
EXEC usp_EmployeeByName 'thomas', 'John'  
  
-- this retrieves EmployeeID 1  
EXEC usp_EmployeeByName 'thomas', 'john'  

另请参阅

内存中 OLTP(内存中优化)