查看以下示例。它表明在unicode字符串(nvarchar)中搜索几乎是在varchar字符串中搜索的八倍。与隐含转换相提并论。寻找解释。或者更有效地在nvarchar字符串中搜索的方法。
use tempdb
create table test
(
testid int identity primary key,
v varchar(36),
nv nvarchar(36),
filler char(500)
)
go
set nocount on
set statistics time off
insert test (v, nv)
select CAST (newid() as varchar(36)),
CAST (newid() as nvarchar(36))
go 1000000
set statistics time on
-- search utf8 string
select COUNT(1) from test where v like '%abcd%' option (maxdop 1)
-- CPU time = 906 ms, elapsed time = 911 ms.
-- search utf8 string using unicode (uses convert_implicit)
select COUNT(1) from test where v like N'%abcd%' option (maxdop 1)
-- CPU time = 6969 ms, elapsed time = 6970 ms.
-- search unicode string
select COUNT(1) from test where nv like N'%abcd%' option (maxdop 1)
-- CPU time = 6844 ms, elapsed time = 6911 ms.
答案 0 :(得分:21)
寻找解释。
NVarchar是16位且Unicode比较规则比ASCII要复杂得多 - 同时支持的各种语言的特殊字符需要引用更多处理。
答案 1 :(得分:2)
我的猜测是LIKE
使用O(n ^ 2)算法而不是O(n)算法实现;它可能必须是领先的%
才能发挥作用。由于Unicode字符串的长度是其两倍,因此这与您的数字一致。
答案 2 :(得分:2)
LIKE %%搜索实现为>和< 。现在更多的行数,更多的处理时间,因为SQL无法真正有效地使用%%的统计数据,如搜索。
此外,unicode搜索需要额外的存储空间以及整理复杂性,它通常不如普通的vanilla varchar搜索效率高。您观察到的最快的整理搜索是二进制整理搜索。
这类搜索最适合全文搜索,或者使用带有内存哈希表的FuzzyLookup实现,以防您拥有大量RAM和非常静态的表。
HTH
答案 3 :(得分:1)
我在SQL Server中看到过类似的问题。有一种情况我使用参数化查询,我的参数是UTF-8(默认在.net),字段是varchar(所以不是utf-8)。最后将每个索引值转换为utf-8只是为了进行简单的索引查找。这可能与整个字符串可能被转换为另一个字符集以进行比较有关。同样对于nvarchar,“a”将与“á”相同,这意味着还有更多的工作可以确定unicode中的2个字符串是否相等。此外,您可能希望使用全文索引,但我不确定这是否可以解决您的问题。
答案 4 :(得分:0)
这是因为Unicode字符的排序规则比非Unicode字符的排序规则复杂。
但是,事情并不像varchar vs nvarchar那样简单
您还必须考虑here中所述的SQL整理与Windows整理。
SQL Server对定义的非Unicode数据执行字符串比较 Windows归类使用Unicode排序规则。因为这些 规则比非Unicode排序规则复杂得多,它们是 更耗费资源。因此,尽管Unicode排序规则是 往往更昂贵,通常在 Unicode数据和使用Unicode定义的非Unicode数据之间的性能 Windows整理。
如上所述,对于Windows排序规则,SQL Server将对varchar使用unicode排序规则,因此不会提高性能。
这里是一个例子:
-- Server default collation is Latin1_General_CI_AS
create table test
(
testid int identity primary key,
v varchar(36) COLLATE Latin1_General_CI_AS, --windows collation
v_sql varchar(36) COLLATE SQL_Latin1_General_CP1_CI_AS, --sql collation
nv nvarchar(36),
filler char(500)
)
go
set nocount on
set statistics time off
insert test (v, nv)
select CAST (newid() as varchar(36)),
CAST (newid() as nvarchar(36))
go 1000000
set statistics time on
-- search utf8 string
select COUNT(1) from test where v_sql like '%abcd%' option (maxdop 1)
-- CPU time = 625 ms, elapsed time = 620 ms.
-- search utf8 string
select COUNT(1) from test where v like '%abcd%' option (maxdop 1)
-- CPU time = 3141 ms, elapsed time = 3389 ms.
-- search utf8 string using unicode (uses convert_implicit)
select COUNT(1) from test where v like N'%abcd%' option (maxdop 1)
-- CPU time = 3203 ms, elapsed time = 3209 ms.
-- search unicode string
select COUNT(1) from test where nv like N'%abcd%' option (maxdop 1)
-- CPU time = 3156 ms, elapsed time = 3151 ms.
如您所见,使用Windows排序规则的varchar和nvarchar没有区别。
注意:似乎只包括SQL排序规则用于遗留目的,不应将其用于新项目(即使它们似乎具有更好的性能)。