【问题标题】:Is predefined query more efficient than ad-hoc SQL query using ADO.NET?预定义查询是否比使用 ADO.NET 的即席 SQL 查询更有效?
【发布时间】:2015-10-07 19:02:57
【问题描述】:

我们有一个表CroppedImage,其中有IdPosXPosYWidthHeigth 列,数据类型为tinyint,另一列CroppedPicture,数据类型为varbinary .

这是临时的方式:

List<int> GetList = GetTopNecessaryImages();
for(int i = 0; i < 100; i++){
    com.CommandText = "select * from CroppedImage where Id=" + GetList[i];
    using (SqlDataReader objSqlDtReader = com.ExecuteReader()) 
    {
        while(objSqlDtReader.Read()) 
        {
             CropImage objCrop = new CropImage ();
             CropImage.Img = (objSqlDtReader["CroppedPicture"]);
        }
    }
}

这是带有参数的预定义查询。

List<int> GetList = GetTopNecessaryImages();
for(int i = 0; i < 100; i++){
    com.CommandText = "select * from CroppedImage where Id=@IdPar";
    com.Parameters.AddWithValue("@IdPar", GetList[i]);
    using (SqlDataReader objSqlDtReader = com.ExecuteReader()) 
    {
        while(objSqlDtReader.Read()) 
        {
             CropImage objCrop = new CropImage (); 
             CropImage.Img = (objSqlDtReader["CroppedPicture"]);
        }
    }
}

Image 字段小于 250KB。 我已经对它们进行了测试,并且在我的机器上没有发现任何差异,但是数据库管理员告诉我,即席查询比托管 SQL 的服务器上预定义的查询消耗更多的内存。 这是真的 ?这两个选项在性能上有什么不同吗?

【问题讨论】:

  • 现实情况是您的 DBA 不正确。这些都是临时查询。 Ad-hoc 查询获取为它们创建的执行计划,并且它们像存储过程的执行计划一样被缓存。第二种方法是首选,因为您正在使用参数化查询并防止 sql 注入。我确实看到的是您正在使用 AddWithValue。这应该避免,因为它有时会出错。 blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
  • 您的 DBA 的意思可能是,不必编译“预定义”(=预编译)视图(或存储过程或表值函数)。但是这样一个简单的查询在任何情况下都很快......(至少如果“Id”上有索引;-))
  • 即使您的 DBA 意味着存储过程或视图,但这并不意味着它会神奇地更快。它们都归结为创建(或重用,如果存在)执行计划。
  • 正如您所说,这些图像很小,您一次选择一个。发送的 250k 图像几乎没有 ram 消耗。一旦查询执行,sql server 就会将其丢弃。老实说,我认为最大的问题是您执行此过程 RBAR。您应该一次性提取所需的所有数据,而不是一遍又一遍地查询。这将大大减轻 sql 框的压力。

标签: sql sql-server ado.net sqldatareader datareader


【解决方案1】:

实际上,您的 DBA 是正确的,尽管术语有点混乱。这更多是参数化查询与非参数化查询的问题。

在参数化查询("select * from CroppedImage where Id=@IdPar")的情况下,即使使用不同的参数多次执行该查询,该查询也只需要由 SQL Server 解析和编译一次。查询的任何后续执行都将重用缓存中的相同查询计划。

相比之下,非参数化查询 ("select * from CroppedImage where Id=" + GetList[i]) 每次使用不同的 GetList[i] 值执行时都将被视为完全不同的查询。在这种情况下,每次都会在 SQL Server 上解析和重新编译查询。这将消耗更多内存,因为数据库服务器现在必须缓存多个查询计划而不是一个。

对于少量查询,差异不会很明显。但是一旦交易量很大,您可能会开始注意到对速度和内存的影响。

这是一篇有趣的文章,提供了有关此问题的更多详细信息:Use SQL Parameters to Overcome Ad Hoc Performance Issues

【讨论】:

    【解决方案2】:

    现实情况是您的 DBA 不正确。这些都是临时查询。即席查询获得为它们创建的执行计划,并且它们像存储过程的执行计划一样被缓存。第二种方法是首选,因为您正在使用参数化查询并防止 sql 注入。我看到的是你正在使用 AddWithValue。这应该避免,因为它有时会出错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      相关资源
      最近更新 更多