簡體   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