预定义查询是否比使用 ADO.NET 的即席 SQL 查询更有效?
Is predefined query more efficient than ad-hoc SQL query using ADO.NET?
我们有一个 table CroppedImage
,它有 Id
、PosX
、PosY
、Width
、Heigth
列数据类型为 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是不正确的。这些都是临时查询。即席查询获得为它们创建的执行计划,并且它们像存储过程的执行计划一样被缓存。首选第二种方法,因为您正在使用参数化查询并防止 sql 注入。不过我看到的是您正在使用 AddWithValue。应该避免这种情况,因为它有时会出错。
实际上,您的 DBA 是正确的,尽管术语有点混乱。这更多是参数化查询与非参数化查询的问题。
在参数化查询("select * from CroppedImage where Id=@IdPar"
)的情况下,即使您使用不同的参数多次执行此查询,查询也只需要由SQL服务器解析和编译一次。查询的任何后续执行都将重用缓存中的相同查询计划。
相比之下,非参数化查询 ("select * from CroppedImage where Id=" + GetList[i]
) 每次使用不同的 GetList[i]
值执行时都会被视为完全不同的查询。在这种情况下,每次都会在 SQL 服务器上解析和重新编译查询。这将消耗更多内存,因为数据库服务器现在必须缓存多个查询计划而不是一个。
对于少量查询,差异不会很明显。但是,一旦您的交易量很大,您可能会开始注意到对速度和内存的影响。
这是一篇有趣的文章,提供了有关此事的更多详细信息:Use SQL Parameters to Overcome Ad Hoc Performance Issues。
我们有一个 table CroppedImage
,它有 Id
、PosX
、PosY
、Width
、Heigth
列数据类型为 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是不正确的。这些都是临时查询。即席查询获得为它们创建的执行计划,并且它们像存储过程的执行计划一样被缓存。首选第二种方法,因为您正在使用参数化查询并防止 sql 注入。不过我看到的是您正在使用 AddWithValue。应该避免这种情况,因为它有时会出错。
实际上,您的 DBA 是正确的,尽管术语有点混乱。这更多是参数化查询与非参数化查询的问题。
在参数化查询("select * from CroppedImage where Id=@IdPar"
)的情况下,即使您使用不同的参数多次执行此查询,查询也只需要由SQL服务器解析和编译一次。查询的任何后续执行都将重用缓存中的相同查询计划。
相比之下,非参数化查询 ("select * from CroppedImage where Id=" + GetList[i]
) 每次使用不同的 GetList[i]
值执行时都会被视为完全不同的查询。在这种情况下,每次都会在 SQL 服务器上解析和重新编译查询。这将消耗更多内存,因为数据库服务器现在必须缓存多个查询计划而不是一个。
对于少量查询,差异不会很明显。但是,一旦您的交易量很大,您可能会开始注意到对速度和内存的影响。
这是一篇有趣的文章,提供了有关此事的更多详细信息:Use SQL Parameters to Overcome Ad Hoc Performance Issues。