Хотя оба выполняют sql, ожидается, что ExecuteReader
возвратит записи, в то время как ExecuteNonQuery
затронет количество записей.Следовательно, оба они разные. Но внутренне то, насколько они различны, зависит от конкретной реализации поставщика.Вы можете использовать ExecuteReader
в одиночку для всех ваших действий с БД , потому что это просто сработало (до сих пор), но, поскольку это не документировано , это не совсем правильный подход для .Вы могли бы быть более ясным о своем намерении с ExecuteNonQuery
.
Что касается производительности, я не думаю, что есть разница вообще.Я попытался с SQLite
, MySqlClient
, SqlClient
, SqlServerCe
и VistaDb
и не увидел заметной разницы в пользу.И все они должны использовать ExecuteReader
внутренне так или иначе.
Основы:
SqlClient:
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;
}
и
MySqlClient:
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
, тогда как SqlClient
делает только для определенных условий. Имейте в виду, insert
с и update
с редко являются узким местом (часто это select
с).
Как я уже сказал, вы не получите номерстрок, затронутых с помощью ExecuteReader
, поэтому лучше использовать ExecuteNonQuery
для выполнения запросов . Более прямая замена на ExecuteReader
будет иметь значение ExecuteScalar
, которое возвращает данные в первом столбце чтения первой строки.
Основы:
SqlClient:
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);
}
}
и
MySqlClient:
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
для ExecuteScalar
и никакой разницы в производительности вообще.