どちらもSQLを実行しますが、影響を受けるレコードの数ExecuteReader
中にレコードを返すことが期待されExecuteNonQuery
ます。したがって、両者は異なります。ただし、内部的には、ベンダー固有の実装によって異なります。(今まで)機能していたのでExecuteReader
、すべてのdbアクションに単独で使用できましたが、文書化されていないため、実際には正しいアプローチではありません. を使用すると、意図がより明確になります。ExecuteNonQuery
パフォーマンスを考える限り、私はまったく違いはないと思います。SQLite
、MySqlClient
、SqlClient
、SqlServerCe
およびで試してみましたが、VistaDb
いずれも好ましい違いは見られませんでした。そして、それらはすべて何らかの方法でExecuteReader
内部的に使用する必要があります。
必需品:
Sql クライアント:
private int InternalExecuteNonQuery(DbAsyncResult result, string methodName, bool sendToPipe)
{
if (!this._activeConnection.IsContextConnection)
{
if (this.BatchRPCMode || CommandType.Text != this.CommandType || this.GetParameterCount(this._parameters) != 0)
{
Bid.Trace("<sc.SqlCommand.ExecuteNonQuery|INFO> %d#, Command executed as RPC.\n", this.ObjectID);
SqlDataReader sqlDataReader = this.RunExecuteReader(CommandBehavior.Default, RunBehavior.UntilDone, false, methodName, result);
if (sqlDataReader == null)
{
goto IL_E5;
}
sqlDataReader.Close();
goto IL_E5;
}
IL_B5:
this.RunExecuteNonQueryTds(methodName, flag);
}
else
{
this.RunExecuteNonQuerySmi(sendToPipe);
}
IL_E5:
return this._rowsAffected;
}
と
MySql クライアント:
public override int ExecuteNonQuery()
{
int records = -1;
#if !CF
// give our interceptors a shot at it first
if ( connection != null &&
connection.commandInterceptor != null &&
connection.commandInterceptor.ExecuteNonQuery(CommandText, ref records))
return records;
#endif
// ok, none of our interceptors handled this so we default
using (MySqlDataReader reader = ExecuteReader())
{
reader.Close();
return reader.RecordsAffected;
}
}
MySqlClient
あなたが直接見ることができるように、呼び出しは特定の条件に対してのみ行われますExecuteReader
。sとs がボトルネックになることはめったにないことに注意してください (多くの場合s です)。SqlClient
insert
update
select
私が言ったように、 の助けを借りても影響を受ける行数は得られないので、より良いクエリをExecuteReader
使用ExecuteNonQuery
してください。より直接的な置き換えExecuteReader
はExecuteScalar
、最初に読み取った行の最初の列のデータを返すものです。
必需品:
Sql クライアント:
override public object ExecuteScalar()
{
SqlConnection.ExecutePermission.Demand();
// Reset _pendingCancel upon entry into any Execute - used to synchronize state
// between entry into Execute* API and the thread obtaining the stateObject.
_pendingCancel = false;
SqlStatistics statistics = null;
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.sqlcommand.executescalar|api> %d#", ObjectID);
try
{
statistics = SqlStatistics.StartTimer(Statistics);
SqlDataReader ds = RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar);
object retResult = null;
try
{
if (ds.Read())
{
if (ds.FieldCount > 0)
{
retResult = ds.GetValue(0);
}
}
return retResult;
}
finally
{
// clean off the wire
ds.Close();
}
}
finally
{
SqlStatistics.StopTimer(statistics);
Bid.ScopeLeave(ref hscp);
}
}
と
MySql クライアント:
public override object ExecuteScalar()
{
lastInsertedId = -1;
object val = null;
#if !CF
// give our interceptors a shot at it first
if (connection != null &&
connection.commandInterceptor.ExecuteScalar(CommandText, ref val))
return val;
#endif
using (MySqlDataReader reader = ExecuteReader())
{
if (reader.Read())
val = reader.GetValue(0);
}
return val;
}
したがって、ExecuteReader
forを使用しても問題はExecuteScalar
なく、パフォーマンスの違いはまったくありません..