SQL Server 不区分大小写的排序规则

Posted

技术标签:

【中文标题】SQL Server 不区分大小写的排序规则【英文标题】:SQL Server case insensitive collation 【发布时间】:2011-05-11 09:50:34 【问题描述】:

在 SQL Server 中使用不区分大小写的排序规则有哪些优点/缺点(就查询性能而言)?

我有一个当前使用不区分大小写的排序规则的数据库,我不太喜欢它。我非常想将其更改为区分大小写。更改排序规则时应该注意什么?

【问题讨论】:

【参考方案1】:

如果您更改数据库的排序规则,您还必须单独更改每列的排序规则 - 他们维护创建表时有效的排序规则设置。

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

【讨论】:

+1。这是很好的信息。不知道如果更改数据库排序规则,个别列也需要修改。【参考方案2】:

(我将此作为单独的答案添加,因为它与我的第一个答案大不相同。) 好的,找到了一些实际的文档。这个MS KB article 表示不同排序规则之间存在 性能差异,但不是你想的那样。 SQL 排序规则(向后兼容,但不支持 unicode)和 Windows 排序规则(支持 unicode)之间的区别:

通常,Windows 和 SQL 排序规则之间的性能差异程度不会很显着。仅当工作负载受 CPU 限制,而不是受 I/O 或网络速度的限制时,差异才会出现,并且这种 CPU 负担大部分是由 SQL Server 中执行的字符串操作或比较的开销引起的。

SQL 和 Windows 排序规则都有区分大小写和不区分大小写的版本,因此听起来这不是主要问题。

Dan 题为“Collation Hell”的优秀文章中的另一个“来自战壕”的好故事:

我继承了一个混合排序规则环境,其中的排序规则数量多得我数不过来。不同的排序规则需要变通方法来避免“无法解决排序规则冲突”错误,并且这些变通方法会由于非 sargable 表达式而降低性能。处理混合排序规则确实很痛苦,因此我强烈建议您对单个排序规则进行标准化,并且只有在经过深思熟虑后才能偏离。

他总结道:

我个人认为在选择正确的排序规则时甚至不应该考虑性能。我生活在排序规则地狱的原因之一是我的前辈选择二进制排序规则来为我们高度事务性的 OLTP 系统提供每一点性能。除了领先的通配符表扫描搜索之外,我发现我们的不同排序规则没有可测量的性能差异。性能的真正关键是查询和索引调优,而不是排序规则。如果性能对您很重要,我建议您在根据性能预期选择排序规则之前对实际应用程序查询执行性能测试。

希望这会有所帮助。

【讨论】:

感谢您收集这些信息。我认为很明显,更改排序规则并不值得我花时间。【参考方案3】:

我想说,在生产数据库中更改为区分大小写的排序规则的最大缺点是,您的许多(如果不是大多数)查询都会失败,因为它们目前被设计为忽略大小写。

我没有尝试更改现有数据库的排序规则,但我怀疑这样做也可能非常耗时。在该过程发生时,您可能必须完全锁定您的用户。除非您在 dev 上进行了彻底的测试,否则不要尝试此操作。

【讨论】:

不,它当然必须在 dev/qa 环境中经过严格的测试。但是,您认为更改带来的性能提升是否足以值得麻烦? 这取决于现有数据库的复杂性以及您可能获得的实际性能提升。尝试使用所需的排序规则创建数据库的单独副本,并测试您认为会提高性能的查询。 我非常鄙视区分大小写的数据库。使我的工作(作为 DBA)变得更加困难。 “什么意思,没有找到列,它是对的!@%@# 那里!!” 每个数据库都应该区分大小写,不应该存在不区分大小写查询的选项。如果列名为“Column”,则它既不是“column”也不是“COLUMN”。 @Klaus:我不会对您的业务需求提出异议(尽管我从不关心区分上下)。然而,就性能而言,在区分大小写的数据库中意外设计性能不佳的查询要容易得多。 WHERE UPPER(GivenName) = 'PETER' 将进行全表扫描。见sqlservercode.blogspot.com/2007/05/…【参考方案4】:

我找不到任何东西来确认正确构造的查询在区分大小写和不区分大小写的数据库上是否工作得更快(尽管我怀疑差异可以忽略不计),但有几件事很清楚对我来说:

    如果您的业务需求没有要求,那么您就是在做很多额外的工作(这是 HLGEM 和 Damien_The_Unbeliever 的答案的症结所在)。 如果您的业务需求不要求这样做,那么您可能会犯很多错误。 如果需要 区分大小写 查找,那么在不区分大小写的数据库中构建性能不佳的查询太容易了:

这样的查询:

... 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)

【讨论】:

@BradC:您似乎误读了这篇文章。它涵盖了一种在不区分大小写的列上进行区分大小写搜索的更有效方法,而不是您似乎已经理解的相反方式。但是,您确实提出了一个重要问题,即在区分大小写的列上尝试不区分大小写搜索的可能性。我不相信有一种方法可以有效地做到这一点(即不扫描)。这个问题大大强化了您的观点,即在没有特定业务需求的情况下,不区分大小写的列会更好。【参考方案5】:

如果您更改了数据库排序规则,但没有更改服务器排序规则(结果它们不匹配),请在使用临时表时小心。除非在他们的 CREATE 语句中另有说明,否则他们将使用服务器的默认排序规则而不是数据库的排序规则,这可能会导致 JOIN 或其他与数据库列的比较(假设它们也更改为数据库的排序规则,正如 Damien_The_Unbeliever 所暗示的那样)失败。

【讨论】:

以上是关于SQL Server 不区分大小写的排序规则的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 排序规则的影响

修改搜索以使其在 SQL Server 中不区分重音

SQL Server转换数据库的排序规则

SQL Server 列名区分大小写

SQL Server的排序规则在啥时候能够进行设置或修改?

向 PostgreSQL 添加不区分大小写的排序规则