Vin*_*nce 2 c# t-sql sql-server
什么是最好的方法?取回 1 或 0?或者检查查询中的行是否可用?我在为 ExecuteScalar 争论,但对其他答案感兴趣,为什么或为什么不。
//using DataReader.HasRows?
bool result = false;
var cmd = new SqlCommand("select foo, bar from baz where id = 123", _sqlConnection, _sqlTransaction);
cmd.CommandType = System.Data.CommandType.Text;
using (var r = cmd.ExecuteReader())
{
if (r != null && r.HasRows)
{
result = true;
}
}
return result;
//or using Scalar?
bool result = false;
var cmd = new SqlCommand("if exists(select foo, bar from baz where id = 123) select 1 else select 0", _sqlConnection, _sqlTransaction);
cmd.CommandType = System.Data.CommandType.Text;
int i = (int) cmd.ExecuteScalar();
result = i == 1;
return result;
Run Code Online (Sandbox Code Playgroud)
Exists 比 Count 更有效,因为 count 需要扫描所有行以匹配条件并包含在计数中,而存在则不存在。
所以与 ExecuteScalar 存在更好。
更多信息支持这一点:
根据http://sqlblog.com/blogs/andrew_kelly/archive/2007/12/15/exists-vs-count-the-battle-never-ends.aspx
两个查询都扫描了表,但 EXISTS 至少能够进行部分扫描,因为它可以在找到第一个匹配行后停止。因为 COUNT( ) 必须读取整个表中的每一行,以确定它们是否符合条件以及有多少行。那是关键的人。在满足 WHERE 子句条件的第一行之后停止工作的能力是 EXISTS 如此高效的原因。优化器知道这种行为,也可以将其考虑在内。现在请记住,与现实世界中的大多数数据库相比,这些表相对较小。所以 COUNT() 查询将在较大的表上成倍增加。您可以轻松地对具有数百万行的表进行数十万次或更多的读取,但 EXISTS 对任何可以使用索引来满足 WHERE 子句的查询仍然只有少量读取。
作为使用 AdventureWorks 和 MSSQL 2012 的简单实验
set showplan_all on
-- TotalSubtreeCost: 0.06216168
select count(*) from sales.Customer
-- TotalSubtreeCost: 0.003288537
select 1 where exists (select * from sales.Customer)
Run Code Online (Sandbox Code Playgroud)
也可以看看
http://sqlmag.com/t-sql/exists-vs-count
更新:关于 ExecuteScalar 与 ExecuteReader。看看 System.Data.SqlClient.SqlCommand 方法的实现上的反汇编器(如 Reflector),显示了一些令人惊讶的东西,它们是等效的:两者最终都调用内部帮助器 内部 SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string 方法, TaskCompletionSource 完成, int timeout, out Task task, bool asyncWrite = false)
它返回一个 SqlDataReader,ExecuteReader 按原样返回它。虽然 ExecuteScalar 使用另一个助手使用它:
private object CompleteExecuteScalar(SqlDataReader ds, bool returnSqlValue)
{
object obj2 = null;
try
{
if (!ds.Read() || (ds.FieldCount <= 0))
{
return obj2;
}
if (returnSqlValue)
{
return ds.GetSqlValue(0);
}
obj2 = ds.GetValue(0);
}
finally
{
ds.Close();
}
return obj2;
}
Run Code Online (Sandbox Code Playgroud)
作为旁注,MySQL Connector/NET(MySQL 的官方 ADO.NET 开源驱动程序)也是如此,方法 ExecuteScalar 在内部创建一个 DataReader(更准确地说是 MySqlDataReader)并使用它。请参阅源文件 /Src/Command.cs(来自https://dev.mysql.com/downloads/connector/net/或https://github.com/mysql/mysql-connector-net)。
总结:关于 ExecuteScalar 和 ExecuteReader 两者都会产生创建 SqlDataReader 的开销,我想说的区别主要是惯用的。
| 归档时间: |
|
| 查看次数: |
2563 次 |
| 最近记录: |