We have the following setup:
- Source server version 12 or 15, collation Latin1_General_CI_AS (in our responsibility, we can change everything here)
- Linked-server version 13, collation: Latin1_General_CI_AS (not in our responsibility, we cannot change anything here)
- Linked database collation: SQL_Latin1_General_CP1_CI_AS
- NHibernate is used as ORM to create queries (that means: less flexibility), with only few to the tables on the linked server.
Linked server options: sp_addlinkedserver @server = N'MyLinkedServer', @srvproduct=N'SQL Server'
'collation compatible='false', 'data access='true', 'dist='false', 'pub='false', 'rpc='false', 'rpc out='false', 'sub='false', 'connect timeout='0', 'collation name=ull, 'lazy schema validation='false', 'query timeout='0', 'use remote collation='true', 'remote proc transaction promotion='true'
The target table TargetTableOnLinkedServer columns look like this:
PrimaryKey varchar(23)
OtherThing varchar(42)
We issue a query like this:
SELECT OtherThing FROM TargetTableOnLinkedServer WHERE PrimaryKey = 'Hello World'
We also try with sp_execute
with the parameter as varchar(8000) - more detailled queries below.
In the SQL server profiler we see that the linked query is being translated to basically:
SELECT OtherThing FROM TargetTableOnLinkedServer WHERE PrimaryKey = N'Hello World'
Please note the "N" here. The "N" (as in Nvarchar) causes an index scan, instead of an index seek. Unfortunately, we cannot find a way to supress the N nor know the reason.
Is there a way to prevent that the "linked-server mechanism" 'converts' the parameter to an unicode string (by adding the N).
Thanks in advance!
In more detail the queries:
SELECT MyColumn FROM MyLinkedServer.MyDatabase.dbo.MyTable A WHERE A.MyColumn = 'MyValue'
This results in a profiler SP:StmtCompleted event on the linked server
SELECT "Tbl1001"."MyColumn" "Col1003" FROM "MyDatabase"."dbo"."MyTable" "Tbl1001" WHERE "Tbl1001"."MyColumn"=N'MyValue'
And an RPC:Completed Event:
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 creates queries like this:
EXEC sp_executesql N'SELECT MyColumn FROM MyLinkedServer.MyDatabase.dbo.MyTable A WHERE A.MyColumn = @p1',N'@p1 varchar(8000)', @p1='MyValue'
Please note the varchar and the lack of an "N". This causes the following query with an index scan (at least this shows the execution plan when I copy-paste the query in 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
Correct would be the following with an index seek:
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
I also tried using another provider MSOLEDBSQL (apparently the most modern one), no changes:
EXEC master.dbo.sp_addlinkedserver @server = N'MyServer', @srvproduct=N'', @provider=N'MSOLEDBSQL', @provstr=N'Server=MyServerName'