【问题标题】:AddWithValue without DBType causing queries to run slowly没有 DBType 的 AddWithValue 导致查询运行缓慢
【发布时间】:2008-12-05 22:04:29
【问题描述】:

我一直在使用 cmd.Parameters.AddWithValue,并且没有指定 DBType(int、varchar、...)来运行查询。查看 SQL Profiler 后,使用此方法运行的查询似乎比指定数据类型时运行得慢很多。

为了让您了解它的速度有多慢,这里有一个示例。该查询是对单个表的简单查找,并且对 where 语句中的列进行索引。指定数据类型时,某个查询运行大约 0 MS(对于 sql server 来说太小无法测量),并且需要 41 次读取。当我删除 DBType 时,完成查询可能需要大约 200 毫秒和 10000 次读取。

我不确定是否只是 SQL Profiler 误报了值,或者这些值实际上是否正确,但它是可重现的,因为我可以添加和删除 DBType,它会生成 SQL Profiler 中给出的值。

有没有其他人遇到过这个问题,以及解决它的简单方法。我意识到我可以在整个代码中添加数据类型,但这似乎需要添加很多东西,如果有更简单的方法来修复它,那将不胜感激。

[编辑]

经过一些初始测试(在循环中运行两个场景)后,分析器给出的值似乎是准确的。

正如添加的信息一样,我在 Windows XP Pro 上运行 .Net 2.0,在 Windows 2000 上运行 SQL Server 2000 用于 DB。

[更新]

经过一番挖掘,我找到了这个blog post,这可能是相关的。似乎 .Net 中的字符串值(因为它们是 unicode)被自动创建为 nvarchar 参数。我将不得不等到星期一开始工作,看看我是否可以解决这个问题。似乎我必须设置数据类型,这是我试图避免的。

这个问题并没有出现在我所做的每个查询中,只是选择了几个,所以我仍然可能只是求助于在有问题的查询中设置 DBType,但我正在寻找一个更通用的解决方案来解决这个问题.

【问题讨论】:

    标签: .net sql ado prepared-statement


    【解决方案1】:

    问题与 SQL Server 如何进行隐式类型转换有关。如果您使用 NVARCHAR 值(即 N'some text')过滤 VARCHAR 列,SQL 将别无选择,只能将该列转换为 NVARCHAR,因为 NVARCHAR 无法隐式转换回 VARCHAR。

    您最好的解决方法是指定类型或将您的数据库列更改为 NVARCHAR。

    【讨论】:

      【解决方案2】:

      我刚刚遇到了这个确切的问题。我有一个带有很多 char 列的旧数据库。在不指定列类型的情况下,我的一个查询的结果需要几分钟时间。 (默认为 nvarchar。)指定列类型导致结果需要几秒钟。

      cmd.Parameters.AddWithValue("charcolumn", "stringvalue");
      cmd.Parameters[0].SqlDbType = SqlDbType.Char;
      

      我想我会尝试将每个字符串查询都设为 char 类型,看看效果如何。

      更新

      其实看完this博文后:archive

      为什么 ADO.Net 这么慢?

      由于 .Net 中的字符串是 unicode,因此这些类型被映射到 NVARCHAR,如果基础列恰好是 VARCHAR 类型,SQL Server 将在每次查询中再次使用比较运算符之前将整个列转换为 NVARCHAR!这会导致很多不必要的 IO,如果我们知道输入字符串可以很容易地写成 VARCHAR。换句话说:从 NVARCHAR 变量声明中删除 N 将我们的查询性能提高了至少 20 倍!

      解决方案!

      cmd.CommandText = "SELECT * FROM dbo.adonetdemo WHERE trackingstring = @tstring";
      cmd.Parameters.AddWithValue("tstring","4E0A-4F89-AE");
      cmd.Parameters[0].DbType = System.Data.DbType.AnsiString;
      

      我决定采用这个解决方案:

      cmd.Parameters.AddWithValue(colName, val);
      if(val is string)
        cmd.Parameters[i].DbType = DbType.AnsiString;
      

      【讨论】:

      • 您发布的链接不存在。可以更新吗?
      • @LuisFilipe: DbType 与数据库无关,因此可以与其他支持方法一起使用。至少我假设这就是他所指的。
      • @Guvante:我只是要求剃须刀更新链接,如果可能的话。
      • 抱歉,我不维护我链接到的网站,所以我无法帮助/更新链接。
      【解决方案3】:

      这两种情况下生成的SQL语句是什么?

      我怀疑当您没有明确指定它时,它会将值假定为 varchar。

      例如SELECT OrderId FROM Orders WHERE OrderId = 1001
      SELECT OrderId FROM Orders WHERE OrderId = '1001'

      【讨论】:

      • 有问题的参数实际上是一个varchar字段,所以我认为这不是问题。
      猜你喜欢
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多