2259 Stimmen

Was ist das "N+1 Selects-Problem" bei ORM (Object-Relational Mapping)?

Das "N+1-Selects-Problem" wird im Allgemeinen als Problem in Diskussionen über objektrelationale Zuordnungen (ORM) genannt, und ich verstehe, dass es etwas damit zu tun hat, dass man viele Datenbankabfragen für etwas machen muss, das in der Objektwelt einfach erscheint.

Hat jemand eine genauere Erklärung für dieses Problem?

2 Stimmen

Es gibt einige hilfreiche Beiträge, die sich mit diesem Problem und der möglichen Lösung befassen. Häufige Anwendungsprobleme und deren Behebung: Das Select N + 1 Problem , Die (silberne) Kugel für das N+1 Problem , Langsames Laden - eifriges Laden

0 Stimmen

Für alle, die nach einer Lösung für dieses Problem suchen, habe ich einen Beitrag gefunden, der es beschreibt. stackoverflow.com/questions/32453989/

54 Stimmen

Wenn man die Antworten bedenkt, sollte man dies nicht als 1+N Problem bezeichnen? Da es sich um eine Terminologie zu handeln scheint, frage ich nicht speziell OP.

40voto

JfredoJ Punkte 2674

Es ist viel schneller, 1 Abfrage zu stellen, die 100 Ergebnisse liefert, als 100 Abfragen zu stellen, die jeweils 1 Ergebnis liefern.

33voto

rorycl Punkte 1304

Wegen dieses Problems sind wir vom ORM in Django abgekommen. Im Grunde genommen, wenn Sie versuchen und tun

for p in person:
    print p.car.colour

Der ORM gibt gerne alle Personen zurück (typischerweise als Instanzen eines Person-Objekts), aber dann muss er die Autotabelle für jede Person abfragen.

Ein einfacher und sehr effektiver Ansatz hierfür ist das, was ich als " Leporello-Faltung "Damit wird die unsinnige Vorstellung vermieden, dass Abfrageergebnisse aus einer relationalen Datenbank auf die Originaltabellen zurückgeführt werden sollten, aus denen die Abfrage zusammengestellt wurde.

Schritt 1: Breite Auswahl

  select * from people_car_colour; # this is a view or sql function

Dies ergibt etwas wie

  p.id | p.name | p.telno | car.id | car.type | car.colour
  -----+--------+---------+--------+----------+-----------
  2    | jones  | 2145    | 77     | ford     | red
  2    | jones  | 2145    | 1012   | toyota   | blue
  16   | ashby  | 124     | 99     | bmw      | yellow

Schritt 2: Objektivieren

Saugen Sie die Ergebnisse in ein generisches Objekt Creator mit einem Argument zu teilen nach dem dritten Element. Das bedeutet, dass das Objekt "jones" nicht mehr als einmal erstellt wird.

Schritt 3: Rendern

for p in people:
    print p.car.colour # no more car queries

Siehe diese Webseite für eine Implementierung von Leporello-Faltung für Python.

23voto

Joe Dean Punkte 3326

Hier ist eine gute Beschreibung des Problems

Nachdem Sie nun das Problem verstanden haben, kann es in der Regel vermieden werden, indem Sie einen Join-Fetch in Ihrer Abfrage durchführen. Dies erzwingt im Grunde den Abruf des Lazy-Load-Objekts, so dass die Daten in einer Abfrage anstelle von n+1 Abfragen abgerufen werden. Ich hoffe, das hilft.

19voto

Nathan Punkte 2535

Siehe Ayendes Beitrag zu diesem Thema: Bekämpfung des Select N + 1 Problems in NHibernate .

Grundsätzlich müssen Sie bei Verwendung eines ORM wie NHibernate oder EntityFramework, wenn Sie eine One-to-many-Beziehung (Master-Detail) haben und alle Details für jeden Master-Datensatz auflisten möchten, N + 1 Abfrageaufrufe an die Datenbank vornehmen, wobei "N" die Anzahl der Master-Datensätze ist: 1 Abfrage, um alle Stammsätze zu erhalten, und N Abfragen, eine pro Stammsatz, um alle Details pro Stammsatz zu erhalten.

Mehr Datenbankabfragen bedeuten mehr Latenzzeit und eine geringere Anwendungs-/Datenbankleistung.

ORMs haben jedoch Möglichkeiten, dieses Problem zu vermeiden, vor allem durch JOINs.

14voto

Anoop Isaac Punkte 147

Meiner Meinung nach ist der Artikel aus der Hibernate Pitfall: Warum Beziehungen träge sein sollten ist genau das Gegenteil des realen N+1 Problems.

Wenn Sie eine korrekte Erklärung benötigen, lesen Sie bitte Hibernate - Kapitel 19: Leistungsverbesserung - Abfragestrategien

Abrufen auswählen (Standardeinstellung) ist extrem anfällig für N+1 Selects Problemen anfällig, daher sollten wir vielleicht das join fetching

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X