【发布时间】:2011-05-11 09:50:34
【问题描述】:
在 SQL Server 中使用不区分大小写的排序规则有哪些优点/缺点(就查询性能而言)?
我有一个当前使用不区分大小写的排序规则的数据库,我不太喜欢它。我非常想将其更改为区分大小写。更改排序规则时应该注意什么?
【问题讨论】:
标签: sql-server sql-server-2008 collation
在 SQL Server 中使用不区分大小写的排序规则有哪些优点/缺点(就查询性能而言)?
我有一个当前使用不区分大小写的排序规则的数据库,我不太喜欢它。我非常想将其更改为区分大小写。更改排序规则时应该注意什么?
【问题讨论】:
标签: sql-server sql-server-2008 collation
如果您更改数据库的排序规则,您还必须单独更改每列的排序规则 - 他们维护创建表时有效的排序规则设置。
create database CollTest COLLATE Latin1_General_CI_AI
go
use CollTest
go
create table T1 (
ID int not null,
Val1 varchar(50) not null
)
go
select name,collation_name from sys.columns where name='Val1'
go
alter database CollTest COLLATE Latin1_General_CS_AS
go
select name,collation_name from sys.columns where name='Val1'
go
结果:
name collation_name
---- --------------
Val1 Latin1_General_CI_AI
name collation_name
---- --------------
Val1 Latin1_General_CI_AI
【讨论】:
(我将此作为单独的答案添加,因为它与我的第一个答案大不相同。) 好的,找到了一些实际的文档。这个MS KB article 表示不同排序规则之间存在 性能差异,但不是你想的那样。 SQL 排序规则(向后兼容,但不支持 unicode)和 Windows 排序规则(支持 unicode)之间的区别:
通常,Windows 和 SQL 排序规则之间的性能差异程度不会很显着。仅当工作负载受 CPU 限制,而不是受 I/O 或网络速度的限制时,差异才会出现,并且这种 CPU 负担大部分是由 SQL Server 中执行的字符串操作或比较的开销引起的。
SQL 和 Windows 排序规则都有区分大小写和不区分大小写的版本,因此听起来这不是主要问题。
Dan 题为“Collation Hell”的优秀文章中的另一个“来自战壕”的好故事:
我继承了一个混合排序规则环境,其中的排序规则数量多得我数不过来。不同的排序规则需要变通方法来避免“无法解决排序规则冲突”错误,并且这些变通方法会由于非 sargable 表达式而降低性能。处理混合排序规则确实很痛苦,因此我强烈建议您对单个排序规则进行标准化,并且只有在经过深思熟虑后才能偏离。
他总结道:
我个人认为在选择正确的排序规则时甚至不应该考虑性能。我生活在排序规则地狱的原因之一是我的前辈选择二进制排序规则来为我们高度事务性的 OLTP 系统提供每一点性能。除了领先的通配符表扫描搜索之外,我发现我们的不同排序规则没有可测量的性能差异。性能的真正关键是查询和索引调优,而不是排序规则。如果性能对您很重要,我建议您在根据性能预期选择排序规则之前对实际应用程序查询执行性能测试。
希望这会有所帮助。
【讨论】:
我想说,在生产数据库中更改为区分大小写的排序规则的最大缺点是,您的许多(如果不是大多数)查询都会失败,因为它们目前被设计为忽略大小写。
我没有尝试更改现有数据库的排序规则,但我怀疑这样做也可能非常耗时。在该过程发生时,您可能必须完全锁定您的用户。除非您在 dev 上进行了彻底的测试,否则不要尝试此操作。
【讨论】:
WHERE UPPER(GivenName) = 'PETER' 将进行全表扫描。见sqlservercode.blogspot.com/2007/05/…
我找不到任何东西来确认正确构造的查询在区分大小写和不区分大小写的数据库上是否工作得更快(尽管我怀疑差异可以忽略不计),但有几件事很清楚对我来说:
这样的查询:
... WHERE UPPER(GivenName) = 'PETER'
不会在 GivenName 上使用索引。你会这样想:
... WHERE GivenName = 'PETER' COLLATE SQL_Latin1_General_CP1_CS_AS
会更好,而且确实如此。但为了获得最佳性能,您必须执行以下操作:
... WHERE GivenName = 'PETER' COLLATE SQL_Latin1_General_CP1_CS_AS
AND GivenName LIKE 'PETER'
(详见this article)
【讨论】:
如果您更改了数据库排序规则,但没有更改服务器排序规则(结果它们不匹配),请在使用临时表时小心。除非在他们的 CREATE 语句中另有说明,否则他们将使用服务器的默认排序规则而不是数据库的排序规则,这可能会导致 JOIN 或其他与数据库列的比较(假设它们也更改为数据库的排序规则,正如 Damien_The_Unbeliever 所暗示的那样)失败。
【讨论】: