最好的方法是什么?获得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;
答案 0 :(得分:4)
Exists比Count更有效,因为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)
另见
http://sqlmag.com/t-sql/exists-vs-count
UPDATE:在ExecuteScalar vs ExecuteReader上。 在System.Data.SqlClient.SqlCommand方法的实现上看一下反汇编程序(如Reflector),显示出一些令人惊讶的东西,它们是等价的:最终都调用了内部帮助器 内部SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,bool returnStream,字符串方法,TaskCompletionSource完成,int超时,out任务任务,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;
}
作为旁注,与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 vs ExecuteReader都会产生创建SqlDataReader的开销,我会说差异主要是惯用的。
答案 1 :(得分:3)
我与ExecuteScalar
一起使用if exists
之类的查询。它应该在服务器上尽可能快,并且网络流量最小。
答案 2 :(得分:1)
如果你只关心存在,我会使用标量方法,但也将TSQL更新为:
SELECT CASE WHEN EXISTS(SELECT ...) THEN 1 ELSE 0 END
答案 3 :(得分:1)
我会使用ExecuteScalar
稍微不同的查询:
string sql = "SELECT CASE WHEN exists(select NULL from baz where id = 123) THEN 1 ELSE 0 END";
var cmd = new SqlCommand(sql, _sqlConnection, _sqlTransaction);