正确的方法将十进制和字符串作为SqlParameter传递

时间:2012-01-28 16:31:00

标签: .net tsql decimal sqlclient

我正在为某些项目创建可重用的SQL Server数据访问层。我有一个问题,找到一个正确的方法来传递.NET decimal作为查询参数。最明显的方式:

cmd.Parameters.AddWithValue("@P0", parameterValue);

效果差不多。该值正确存储在DB中,但SqlClient从实际值推断出确切类型,因此当应用程序通过12345.678时,它将@ P0声明为NUMERIC(8,3)。当完全相同的查询与其他值一起使用时,将声明该值的精度和比例。由于我不知道的原因,从SQL Server那些查询不相同,并且每个查询都在sys.dm_exec_cached_plans中获得单独的条目。 string存在完全相同的问题 - 对于每个长度,都有不同的查询计划。

我们的一些应用程序每分钟写入相当多的记录,每个记录具有5-10个decimal值,其范围变化很​​大(某些传感器数据,某些货币值)。几乎每个INSERT都有它自己的查询计划,经过一天后,缓存了相同查询计划的超过100k版本,占用了超过几GB的RAM。

我的想法是将所有可能的类型合并到一些任意选择的类型。对于decimal,当精度低于20时,我将其设置为20.当精度大于20时,我将其设置为可被实际精度整除4的最小值(例如24,28,32,36)。类似的是缩放(最小2,然后是2步)和字符串(最小128,然后是2的幂)。这种方式似乎可以控制问题 - 我已经看到每个查询的计划大约有100个而不是100k,而SQL Server使用内存用于缓冲池,而不是用于一些无用的计划。

这种方法有什么办法可能出错吗?在使用SqlClient和使用decimals加载的查询时,是否有更好的方法可以控制查询计划缓存?

我不能做的事情清单:

  • 使用存储过程 - 因为此DAL的目的是为许多DBMS(SQL Server,MS Access,Firebird,Oracle)创建抽象层。
  • 强迫我的队友以某种方式将每个变量传递给实际类型 - 因为那样会很残忍。
  • 删除此DAL,使用普通的旧DbProviderFactory并创建类似1990年的参数 - 因为此DAL还处理SQL方言的查询创建,数据库结构创建等。
  • 将此DAL废弃并使用像NHibernate这样的“正确”DAO - 因为它不是在这里发明的。
  • 将此问题提交给dba.stackexchange.com - 因为它是SqlClient的问题以及我使用它的方式,而不是SQL Server本身。

1 个答案:

答案 0 :(得分:2)

您在此处正确识别了关键问题,即让SQL驱动程序为您决定参数的大小,比例和精度。您通过限制参数的精度/比例/大小来减少查询计划数量的想法听起来也是正确的。对于字符串,您可以将大小设置为您期望的最大值:当您的查询将具有较大大小限制的参数字符串与较小大小的varchar进行比较时,它应该可以正常工作。选择几个小数精度也听起来不错。看看你是否可以将它降低到只有一对精度/比例:它可能(它对我们的工作项目非常有效)。如果您设法这样做,您将能够根据SQL查询转到单个查询计划。