我们有一个现有的C#代码体,可以在很多地方调用参数化的临时SQL Server查询.我们从不指定SqlParameter.Size,并且记录了在这种情况下,SqlParameter类从参数值推断出大小.我们最近才意识到这会产生SQL Server计划缓存污染问题,其中为每个不同的参数大小组合缓存单独的计划.
幸运的是,每当我们创建一个SqlParameter时,我们都是通过一个实用方法来实现的,所以我们有机会在该方法中添加几行并使这个问题消失.我们正考虑添加以下内容:
if((sqlDbType == SqlDbType.VarChar) || (sqlDbType == SqlDbType.NVarChar))
m_sqlParam.Size = -1;
Run Code Online (Sandbox Code Playgroud)
换句话说,每次传递varchar参数时,将其作为varchar(max)传递.基于一些快速测试,这很好用,我们可以看到(通过SQL Profiler和sys.dm_exec_cached_plans)每个ad-hoc查询的缓存中现在有一个计划,以及字符串参数的类型现在是varchar(max).
这似乎是一个简单的解决方案,必须有一些隐藏的,破坏性能的缺点.有人知道吗?
(请注意,我们只需要支持SQL Server 2008及更高版本.)
是的,有一个隐藏的,破坏性能的缺点!
非常感谢Martin Smith,他的回答(见下文)向我指出了正确的分析方法.我使用我们的应用程序的Users表进行了测试,该表具有定义为nvarchar(100)的Email列,并且在Email列上具有非聚集索引(IX_Users_Email).我修改了Martin的示例查询,如下所示:
declare @a nvarchar(max) = cast('a' as nvarchar(max))
--declare @a nvarchar(100) = cast('a' as nvarchar(100))
--declare @a nvarchar(4000) = cast('a' as nvarchar(4000))
select Email from Users where Email = @a
Run Code Online (Sandbox Code Playgroud)
根据我取消评论的"声明"语句,我得到了一个非常不同的查询计划.nvarchar(100)和nvarchar(4000)版本都给我一个IX_Users_Email 的索引搜索 - 实际上,我指定的任何长度都给了我相同的计划.另一方面,nvarchar(max)版本为我提供了对IX_Users_Email 的索引扫描,然后是Filter运算符以应用谓词.
这对我来说已经足够了 - 如果有可能进行扫描而不是寻求,那么这种"治愈"比疾病更糟糕.
新提案
我注意到每次SQL Server使用varchar参数参数化查询时,缓存计划只使用varchar(8000)(或nvarchar(4000))作为参数.我认为如果它对SQL Server来说足够好,那对我来说已经足够了!用我原来的问题(上面)替换C#代码:
if(sqlDbType == SqlDbType.VarChar)
m_sqlParam.Size = 8000;
else if(sqlDbType == SqlDbType.NVarChar)
m_sqlParam.Size = …
Run Code Online (Sandbox Code Playgroud) 有没有人有一个工作代码示例显示对Windows颜色系统函数WcsGetDefaultColorProfile的调用来获取特定设备的默认颜色配置文件?当我为pDeviceName参数传递null时,它适用于我,但是当我尝试传递监视器的设备名称时,我总是返回错误代码ERROR_FILE_NOT_FOUND.
我更喜欢C#的例子,但我会接受任何我能得到的东西.我无法在任何地方找到任何新的WCS配置文件管理功能的示例代码.