Параметр в запросе связанного сервера преобразуется из varchar в nvarchar, что приводит к сканированию индекса и снижению производительности - PullRequest
0 голосов
/ 07 февраля 2020

У нас есть следующие настройки:

  • Исходный сервер версии 12 или 15, параметры сортировки Latin1_General_CI_AS (мы можем здесь изменить все)
  • Версия 13 связанного сервера, параметры сортировки: Latin1_General_CI_AS (здесь мы не можем ничего изменить : меньше гибкости), с несколькими таблицами на связанном сервере.
  • Параметры связанного сервера: sp_addlinkedserver @server = N'MyLinkedServer ', @ srvproduct = N' SQL Server '

    'сопоставление совместимо =' false ',' доступ к данным = 'true', 'dist =' false ',' pub = 'false', 'rpc =' false ',' rp c out = 'false ',' sub = 'false', 'connect timeout =' 0 ',' collation name = ull, 'проверка ленивой схемы =' false ',' query timeout = '0', 'use remote collation =' true ',' Remote Pro c продвижение транзакции = 'true'

Таблица назначения * 1 021 * TargetTableOnLinkedServer столбцы выглядят так:

PrimaryKey varchar(23)
OtherThing varchar(42)

Мы выдаем запрос следующим образом:

SELECT OtherThing FROM TargetTableOnLinkedServer WHERE PrimaryKey = 'Hello World'

Мы также пытаемся использовать sp_execute с параметром varchar (8000) ) - более подробные запросы приведены ниже.

В профилировщике сервера SQL мы видим, что связанный запрос переводится в основном:

SELECT OtherThing FROM TargetTableOnLinkedServer WHERE PrimaryKey = N'Hello World'

Пожалуйста, обратите внимание на «N» здесь. «N» (как в Nvarchar) вызывает сканирование индекса, а не поиск индекса. К сожалению, мы не можем найти способ подавления N и не знаем причину.

Есть ли способ предотвратить то, что «механизм связанного сервера» «преобразует» параметр в строку Unicode (путем добавления N ).

Заранее спасибо!


Более подробно запросы:

SELECT MyColumn FROM MyLinkedServer.MyDatabase.dbo.MyTable A WHERE A.MyColumn = 'MyValue'

Это приводит к профилирующему событию SP: StmtCompleted на связанный сервер

SELECT "Tbl1001"."MyColumn" "Col1003" FROM "MyDatabase"."dbo"."MyTable" "Tbl1001" WHERE "Tbl1001"."MyColumn"=N'MyValue'

И RP C: Завершенное событие:

declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,NULL,N'SELECT "Tbl1001"."MyColumn" "Col1003" FROM "MyDatabase"."dbo"."MyTable" "Tbl1001" WHERE "Tbl1001"."MyColumn"=N''MyValue'''
select @p1

NHibernate создает такие запросы:

EXEC sp_executesql N'SELECT MyColumn FROM MyLinkedServer.MyDatabase.dbo.MyTable A WHERE A.MyColumn = @p1',N'@p1 varchar(8000)', @p1='MyValue'

Обратите внимание varchar и отсутствие "N". Это приводит к следующему запросу со сканированием индекса (по крайней мере, это показывает план выполнения, когда я копирую и вставляю запрос в SMSS):

declare @p1 int
exec sp_prepexec @p1 output,N'@P1 nvarchar(4000)',N'SELECT "Tbl1001"."MyColumn" "Col1004" FROM "MyDatabase"."dbo"."MyTable" "Tbl1001" WHERE "Tbl1001"."MyColumn"=@P1',N'MyValue'
select @p1

Правильно будет следующее при поиске по индексу:

exec sp_prepexec @p1 output,N'@P1 varchar(4000)',N'SELECT "Tbl1001"."MyColumn" "Col1004" FROM "MyDatabase"."dbo"."MyTable" "Tbl1001" WHERE "Tbl1001"."MyColumn"=@P1','MyValue'
select @p1

Я также пытался использовать другой поставщик MSOLEDB SQL (очевидно, самый современный), без изменений:

EXEC master.dbo.sp_addlinkedserver @server = N'MyServer', @srvproduct=N'', @provider=N'MSOLEDBSQL', @provstr=N'Server=MyServerName'
...