繁体   English   中英

使用C#检查SQL Server表中是否存在记录的最佳方法是什么?

[英]What is the best way to check if a record exists in a SQL Server table using C#?

什么是最好的方法? 获得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;

存在比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

更新:在ExecuteScalar vs ExecuteReader上。 在System.Data.SqlClient.SqlCommand方法的实现上看一下反汇编程序(如Reflector),显示了一些令人惊讶的东西,它们是等价的:最终调用内部帮助程序内部SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior, bool returnStream,string方法,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的开销,我会说差异主要是惯用的。

我会使用像if exists的查询来使用ExecuteScalar 它应该在服务器上尽可能快,并且网络流量最小。

如果你只关心存在,我会使用标量方法,但也将TSQL更新为:

SELECT CASE WHEN EXISTS(SELECT ...) THEN 1 ELSE 0 END

我会使用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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM