MySQL: Suche nach Zeilen, nicht nehmen Sie Teil in einer Beziehung
Ich habe zwei Tabellen: 'Filme' und 'Benutzer'.
Es gibt eine n:m-Beziehung zwischen denen, die beschreiben, auf welche Filme, die ein Benutzer gesehen hat. Dies ist beschrieben mit einer Tabelle 'sehen'
Jetzt will ich herausfinden, für einen bestimmten Benutzer, alle Filme, die er nicht gesehen hat.
Meine aktuelle Lösung ist wie folgt:
SELECT *
FROM movies
WHERE movies.id NOT IN (
SELECT seen.movie_id
FROM seen
WHERE seen.user_id=123
)
Diese funktioniert aber scheinbar nicht sehr gut skalieren. Gibt es einen besseren Ansatz, um dieses?
- > Dieser funktioniert aber scheinbar nicht sehr gut skalieren. Gibt es eine bessere Lösung für dieses? Haben Sie versucht, die <a href="dev.mysql.com/doc/refman/5.0/en/...> auf dieser Abfrage?
- Wenn es nicht die Skalierung tja, dann sind deine Indizierung ist nicht wirksam. Was sind Ihre Indizes?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist eine typische Möglichkeit, das zu tun diese Abfrage ohne die Unterabfrage Methode, die Sie zeigte. Diese erfüllen können @Godeke verlangen, um zu sehen, eine join-basierte Lösung.
Jedoch in den meisten Marken der Datenbank kann diese Lösung schlechter als die subquery-Lösung. Es ist am besten, um zu ERKLÄREN, zu analysieren, sowohl Abfragen, um zu sehen, welcher besser machen wird gegeben, Ihr schema und Daten.
Hier ist eine weitere variation auf die subquery-Lösung:
Dies ist eine korrelierte Unterabfrage, die müssen ausgewertet werden, für jede Zeile der äußeren Abfrage. In der Regel ist dies teuer, und Ihre original-Beispiel-query ist besser. Auf der anderen Seite, in MySQL "
NOT EXISTS
" ist oft besser als "column NOT IN (...)
"Wieder, müssen Sie testen jede Lösung und vergleichen Sie die Ergebnisse, um sicher zu sein. Es ist eine Verschwendung von Zeit, wählen Sie eine beliebige Lösung ohne Messen der Leistung.
OUTER JOIN
trick. Danke!Nicht nur, dass Ihre Abfrage zu arbeiten, es ist der richtige Ansatz, um das problem, wie bereits erwähnt. Vielleicht finden Sie eine andere Herangehensweise an das problem? Eine einfache BEGRENZUNG auf Ihre äußere select-sollte sehr schnell, auch für große Tabellen, zum Beispiel.
Gesehen ist die join-Tabelle, also ja, das sieht aus wie die richtige Lösung. Sie sind effektiv "Subtraktion" der Satz von Film-IDs GESEHEN (für einen Benutzer) aus der Gesamtheit in FILMEN, was in der unsichtbaren Filme für diesen Benutzer.
Dies nennt man eine "negative Verknüpfung", und leider NICHT IM oder NICHT EXISTIERT, sind die besten Optionen. (Ich würde gerne sehen, eine negative join-syntax, die ähnlich war zu INNER/OUTER/LEFT/RIGHT joins, wo aber die ON-Klausel könnte eine Subtraktion Anweisung).
@Bill ' s Lösung ohne eine Unterabfrage funktionieren sollte, obwohl, wie er bemerkt, ist es eine gute Idee, testen Sie Ihre Lösung für Leistung in beide Richtungen. Ich vermute, dass die Unterabfrage oder nicht, das ganze GESEHEN.ID-index (und natürlich den gesamten FILM.ID-index) wird ausgewertet, in beide Richtungen: es wird davon abhängen, wie der Optimierer verarbeitet es.
Wenn Ihr DBMS dies unterstützt bitmap-Indizes, die Sie könnten versuchen, Sie.