Exists ist effizienter als die Zählung, weil die Zählung alle Zeilen durchsuchen muss, um die Kriterien zu erfüllen und in die Zählung aufzunehmen, existiert nicht.
Also existiert mit ExecuteScalar besser.
Als weitere Informationen dieser Sicherung:
zu http://sqlblog.com/blogs/andrew_kelly/archive/2007/12/15/exists-vs-count-the-battle-never-ends.aspx Nach
Beide Abfragen gescannt, um die Tabelle, aber die VORHANDEN konnte gelinde bei Sie ein Partial-Scan auf die Tatsache, tun es, nachdem es zu stoppen findet die sehr erste passende Zeile. Wo als COUNT () muss jede Zeile in der gesamten Tabelle gelesen werden, um festzustellen, ob sie die Kriterien erfüllen und wie viele sind. Das sind die Schlüsselleute. Die Fähigkeit, nach der ersten Zeile zu stoppen, die die Kriterien der WHERE-Klausel erfüllt, ist , was EXISTS so effizient macht. Der Optimierer weiß von diesem Verhalten und kann das auch einrechnen. Beachten Sie, dass diese Tabellen relativ klein im Vergleich zu den meisten Datenbanken in der realen Welt sind. So würden die Zahlen der COUNT () Abfragen mehrfach auf größeren Tabellen multipliziert werden. Sie könnten leicht Hunderte von Tausenden von Reads oder mehr auf Tabellen mit Millionen von Zeilen bekommen, aber die EXISTS werden immer noch nur haben nur ein paar Lesevorgänge auf Abfragen, die einen Index verwenden können die WHERE-Klausel.
Als ein einfaches Experiment mit Adventure mit 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)
Siehe auch
http://sqlmag.com/t-sql/exists-vs-count
UPDATE: Auf ExecuteScalar vs ExecuteReader. Schauen Sie sich mit einem Disassembler (wie Reflector) die Implementierung von System.Data.SqlClient an.SqlCommand Methoden, zeigt etwas überraschend, sie sind irgendwie gleichwertig: beide am Ende Aufruf der internen Helfer interne SqlDataReader RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, Bool returnStream, string-Methode, TaskCompletionSource Vervollständigung, int Timeout, Task Aufgabe, bool asyncWrite = false)
die einen SqlDataReader zurückgibt, der ExecuteReader gibt es wie es ist zurück. Während ExecuteScalar es mit einem anderen Helfer verbraucht:
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;
}
Als Randbemerkung, gleiche gilt mit MySQL Connector/NET (Der offiziellen ADO.NET Open-Source-Treiber für MySQL), intern die Methode ExecuteScalar erzeugt einen Datareader (MySqlDataReader um genau zu sein) und konsumiert es. Siehe Quelldatei /Src/Command.cs (von https://dev.mysql.com/downloads/connector/net/ oder https://github.com/mysql/mysql-connector-net).
Zusammenfassung: In Bezug auf die ExecuteScalar vs ExecuteReader beide im Overhead der Erstellung eines SqlDataReader entstehen, würde ich sagen, der Unterschied ist meist idiomatisch.
Möchten Sie auch die Ergebnisse der Abfrage oder nur einen Indikator anzeigen, wenn Ergebnisse angezeigt werden? –
Die dritte Option wäre 'select top 1 1 from ...' zu verwenden, was zumindest am einfachsten klingt. Sie sollten trotzdem in Ausführungsplan und Statistikausgabe schauen, wenn Sie interessiert sind, was auf der Datenbankseite passiert. –