Ist das eine schlechte Idee, wird es zuerst alle Datenbankzeilen auswählen und dann die eine finden oder wird es schlau sein und den Kontext sehen, in dem es verwendet wird, und nur die eine Zeile holen.
Grund dafür ist, dass ich nur die Guid- und die Result-Columns zurückgeben möchte.
%Vor%Wie finde ich die Antwort darauf, ohne den Netzwerkfluss oder die Anfragen an die Datenbank überwachen zu müssen?
"wählt zuerst alle Datenbankzeilen aus und sucht dann die eine"
Technisch gesehen, nein, die Kombination von .Select gefolgt von .SingleOrDefault wird das nicht tun. Select () legt die Parameter für die Abfrage fest, ruft jedoch keine Daten ab. Die verzögerte Ausführung von LINQ ruft keine Zeilen ab, bis tatsächlich ein Datenergebnis erzeugt werden muss. Sie können mehrere Abfragen zusammen erstellen (.Wählen Sie (...). Wählen Sie (..) usw.) und nichts ruft tatsächlich Zeilen ab, bis Sie eine Operation ausführen, die Daten wie First () oder .ToList () zurückgibt.
Die Verwendung von Single () kann jedoch dazu führen, dass das gesamte Dataset gescannt wird, um nachzuweisen, dass die übereinstimmende Zeile die einzige übereinstimmende Zeile ist.
Denken Sie darüber nach: Wie weiß die Abfrage, dass die eine Zeile die einzige Zeile in der übereinstimmenden Datenmenge ist? Es muss versuchen, die nächste Zeile zu finden. Wenn es wirklich nur eine Zeile gibt, die im Datensatz mit Millionen übereinstimmt, muss Single () möglicherweise alle diese Millionen von Zeilen durchlaufen, um zu beweisen, dass die aktuelle Übereinstimmung die einzige Übereinstimmung ist.
Wenn es sich bei Ihrem Dataset um SQL handelt und Ihre Daten so indiziert sind, dass die Abfrageoptimierung möglich ist, ist Single () möglicherweise nicht so schlecht. Wenn Ihre SQL-Daten jedoch nicht auf eine Weise indexiert werden, die für diese Abfrage hilfreich ist, kann Single () eine Menge Arbeit für den SQL-Server erzeugen.
Single () ist angemessen, wenn Ihre Programmlogik wirklich wissen muss, dass die zurückgegebene Zeile die einzige Zeile im gesamten Dataset ist. Es gibt jedoch andere Möglichkeiten, die Eindeutigkeit zu garantieren. Wenn Sie für Ihre Daten einen Primärschlüssel einrichten können, der mit Ihrer LINQ-Bedingung übereinstimmt, kann nur eine übereinstimmende Zeile zur Datenbank hinzugefügt / hinzugefügt werden, sodass Sie Single () nicht wirklich benötigen. (Und ironischerweise wird die Leistung von Single () auch in diesem Fall trivial sein, da der Primärschlüssel-Index zur Optimierung der Abfrage verwendet werden kann)
Wenn Sie nur die erste Zeile haben möchten, die der Bedingung entspricht, verwenden Sie First () anstelle von Single (). First () muss nur Zeilen von Daten scannen, bis die erste Übereinstimmung gefunden wird. Es muss nicht weiter nach Zeilen suchen, um zu beweisen, dass die erste Übereinstimmung die einzige Übereinstimmung ist, wie Single ().
Ich bin mir ziemlich sicher, dass dies nicht die gesamte Datenbank vor der Filterung zurückgibt, da die Ausführung der Abfrage nicht vor dem Ausführen der 'evaluation' -Anweisung erfolgt, was der SingleOrDefault () in dieser Abfrage ist.
Wenn du
hättest context.CrawlerQueues.ToList().Select(cq => new{cq.Guid,cq.Result}).SingleOrDefault(cq => cq.Guid == guid)
;
dann würde dies die ToList()
vor dem Filtern auswerten, aber die Abfrage, wie sie ist, ist in Ordnung.
Wenn Sie den Evaluierungspfad oder das generierte SQL aus Ihren LINQ-Anweisungen nicht kennen, ist LINQPad ein sehr gutes Tool, das funktioniert mit Linq, Linq2Sql, EF sehr einfach.
SingleOrDefault
- Gibt das einzige Element einer Sequenz oder einen Standardwert if zurück Die Sequenz ist leer. Diese Methode löst eine Ausnahme aus, wenn mehr als ein Element in der Sequenz vorhanden ist .
FirstOrDefault
- Gibt das erste Element einer Sequenz oder einen Standardwert if zurück Die Sequenz enthält keine Elemente.
Semantisch möchten Sie FirstorDefault
, da Ihre Frage mehrere zurückgegebene Zeilen enthält.
Die tatsächlich ausgeführte Abfrage hängt tatsächlich vom Linq-Provider ab, aber ja, der Linq-Provider wird erst im letzten möglichen Moment ausgewertet, so dass er den Kontext (SingleOrDefault) kennt, bevor er die Abfrage ausführt. Ein guter wird nichts un-notwendig holen.
Eine gute Linq-Implementierung wird tatsächlich zwei Zeilen abrufen, da SingleOrDefault drei Fälle behandelt;