SQL Server использует высокий процессор при поиске внутри строк nvarchar - PullRequest
25 голосов
/ 17 января 2011

Проверьте следующий пример. Это показывает, что поиск в строке юникода (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.

Ответы [ 5 ]

21 голосов
/ 17 января 2011

В поисках объяснения этому.

NVarchar 16-битный и правила сравнения Unicode намного сложнее, чем ASCII - специальные символы для различных языков, которые поддерживаются на одном и том же языке.время требует цитаты еще немного обработки.

2 голосов
/ 17 января 2011

LIKE %% поиск реализован как> и <.Теперь больше количества строк, больше времени обработки, так как SQL не может эффективно использовать статистику для %%-подобных поисков. </p>

Кроме того, поиск в Юникоде требует дополнительного хранилища и, наряду с сложностями сопоставления, обычно небудь так же эффективен, как обычный поиск ванильного варшара.Самый быстрый поиск сопоставления, который вы наблюдали, - это поиск двоичного сопоставления.

Этот вид поиска лучше всего подходит для полнотекстового поиска или реализован с использованием FuzzyLookup с хэш-таблицей в памяти, если у вас много оперативной памятии довольно статичный стол.

HTH

2 голосов
/ 17 января 2011

Я предполагаю, что LIKE реализован с использованием алгоритма O (n ^ 2), а не алгоритма O (n); вероятно, для того, чтобы % заработал. Поскольку строка в Юникоде в два раза длиннее, это соответствует вашим цифрам.

1 голос
/ 17 января 2011

Я видел похожие проблемы в SQL Server.Был случай, когда я использовал параметризованные запросы, и мой параметр был UTF-8 (по умолчанию в .net), а поле было varchar (поэтому не utf-8).В итоге все значения индекса конвертировались в utf-8 просто для простого поиска индекса.Это может быть связано с тем, что вся строка может быть переведена в другой набор символов для сравнения.Также для nvarchar, «a» будет таким же, как «á», что означает, что там будет гораздо больше работы, чтобы выяснить, равны ли 2 строки в юникоде.Кроме того, вы можете использовать полнотекстовое индексирование, хотя я не уверен, решит ли это вашу проблему.

0 голосов
/ 06 июля 2018

Это потому, что правила сортировки символов Unicode более сложны, чем правила сортировки символов не-Unicode.

Но все не так просто, как varchar vs nvarchar

Вы также должны рассмотреть SQL Collation против Windows Collation, как объяснено здесь .

SQL Server выполняет сравнение строк определенных данных не в Юникоде с сортировкой Windows с использованием правил сортировки Unicode. Потому что эти правила гораздо сложнее, чем правила сортировки не в Юникоде, они более ресурсоемкий. Таким образом, хотя правила сортировки Unicode часто дороже, как правило, разница в производительность между данными Unicode и не-Unicode данными, определенными Windows сортировка.

Как уже говорилось, для Windows Collation SQL Server будет использовать правила сортировки Юникода для varchar, следовательно, вы не получите прироста производительности.

Вот пример:

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

Как видите, нет разницы между varchar и nvarchar с сопоставлением окон.

Примечание. Похоже, что параметры сортировки SQL включены только для унаследованных целей и не должны использоваться для новых проектов (даже если кажется, что они имеют более высокую производительность).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...