2009-03-20 13 views
4

Als ein allgemeiner Fall von this question, weil ich denke, dass es für mehr Leute von Interesse sein könnte ... Was ist der beste Weg, um eine Volltextsuche auf zwei Tabellen durchzuführen? Angenommen, es gibt drei Tabellen, eine für Programme (mit übergabe-ID) und jeweils eine für Tags und Beschreibungen mit objekt-ID: Fremdschlüssel, die auf Datensätze in Programmen verweisen. Wir wollen die übergabe-ID von Programmen mit bestimmten Text in ihren Tags ODER Beschreibungen. Aus Gründen, auf die ich hier nicht eingehen werde, müssen wir MATCH GEGEN STELLEN. Lassen Sie sich nicht an diesem Aspekt hängen.MySQL FULLTEXT Suche Across> 1 Tabelle

programs 
    id 
    submitter_id 
tags_programs 
    object_id 
    text 
descriptions_programs 
    object_id 
    text 

Folgende Arbeiten und führt in einem 20ms oder so:

SELECT p.submitter_id 
FROM programs p 
WHERE p.id IN 
    (SELECT t.object_id 
    FROM titles_programs t 
    WHERE MATCH (t.text) AGAINST ('china') 
UNION ALL 
    SELECT d.object_id 
    FROM descriptions_programs d 
    WHERE MATCH (d.text) AGAINST ('china')) 

aber ich versuchte, diese neu zu schreiben als ein JOIN wie folgt und es läuft für eine sehr lange Zeit. Ich muss es nach 60 Sekunden töten.

SELECT p.id 
FROM descriptions_programs d, tags_programs t, programs p 
WHERE (d.object_id=p.id AND MATCH (d.text) AGAINST ('china')) 
OR (t.object_id=p.id AND MATCH (t.text) AGAINST ('china')) 

Nur aus Neugier habe ich das OR mit UND ersetzt. Das läuft auch in wenigen Millisekunden, aber das brauche ich nicht. Was ist falsch mit der obigen zweiten Abfrage? Ich kann mit der UNION und Subselects leben, aber ich würde es gerne verstehen.

Antwort

5

Verbinden Sie sich nach den Filtern (z. B. verbinden Sie die Ergebnisse), nicht versuchen, zu verbinden und dann zu filtern.

Der Grund ist, dass Sie die Verwendung Ihres Volltextindex verlieren.

Klärung in Reaktion auf den Kommentar: Ich verwende das Wort Join generisch hier, nicht als JOIN sondern als Synonym für Zusammenführen oder kombinieren.

Ich sage im Wesentlichen, dass Sie die erste (schnellere) Abfrage oder etwas ähnliches verwenden sollten. Der Grund, warum es schneller ist, ist, dass jede der Unterabfragen ausreichend aufgeräumt ist, dass die Datenbank den Volltextindex der Tabelle verwenden kann, um die Auswahl sehr schnell durchzuführen. Die Verbindung der beiden (vermutlich viel kleineren) Ergebnismengen (mit UNION) ist ebenfalls schnell. Das bedeutet, das Ganze ist schnell.

Die langsame Version läuft durch viele Daten und testet es, um zu sehen, ob es das ist, was Sie wollen, anstatt die Daten schnell zu löschen und nur durch Zeilen zu suchen, die Sie wahrscheinlich wirklich wollen.

+0

Ist die Syntax für das andere als das erste Beispiel? –

+0

Ich folge nicht, Markus. (a) Wie würdest du schreiben "mach dich nach den Filtern?" und (b) "Sie verlieren die Nutzung Ihres Volltextindexes. ??? –

0

Wenn Sie beide Tabellen verbinden, haben Sie am Ende viele Datensätze zu inspizieren. Wenn zum Beispiel beide Tabellen 100.000 Datensätze haben, ergeben sich bei vollständiger Verknüpfung 10.000.000.000 Datensätze (10 Milliarden!).

Wenn Sie das OR durch AND ändern, dann lässt die Engine alle Datensätze aus der Tabelle descriptions_programs ausfiltern, die nicht mit "china" übereinstimmen, und nur und dann, die mit titles_programs verknüpft sind.

Wie auch immer, das ist nicht das, was Sie brauchen, also würde ich empfehlen, an der UNION-Methode festzuhalten.

+0

Ist das richtig? Wenn ich 100.000 Programme habe und jeder einen Titel hat, warum würde der Join von Programmen und Tags nicht gerade 100.000 Zeilen ergeben? Und wenn Sie auch 100.000 Beschreibungen beitreten, haben Sie nicht immer noch nur 100.000 Zeilen? –

+0

Wenn Sie Programme mit Titeln abgleichen möchten, dann passen Sie sie in der Join-Klausel an. Wenn Sie sie nur ohne eine ON-Klausel verknüpfen, werden alle Zeilen abgeglichen. So etwas wie FROM descriptions_programs d JOIN tags_programs t ON d.object_id = t.objecT_id JOIN-Programme p ON t.object_id = p.id – Seb

0

Die Vereinigung ist der richtige Weg zu gehen. Der Join wird beide Volltextindizes gleichzeitig abrufen und kann die Anzahl der tatsächlich ausgeführten Überprüfungen multiplizieren.

1

Nur für den Fall, dass Sie nicht wissen: MySQL hat eine eingebaute Anweisung namens EXPLAIN, die verwendet werden kann, um zu sehen, was unter der Oberfläche vorgeht. Es gibt eine Menge Artikel darüber, daher werde ich nicht ins Detail gehen, aber für jede Tabelle gibt es eine Schätzung für die Anzahl der Zeilen, die es verarbeiten muss. Wenn Sie sich die Spalte "rows" im EXPLAIN-Ergebnis für die zweite Abfrage ansehen, werden Sie wahrscheinlich feststellen, dass die Anzahl der Zeilen ziemlich groß und sicherlich viel größer als die der ersten ist.

Das Netz ist voller Warnungen über die Verwendung von Unterabfragen in MySQL, aber es stellt sich heraus, dass der Entwickler oft schlauer als der MySQL-Optimierer ist. Das Filtern von Ergebnissen in einer gewissen Weise vor dem Verbinden kann in vielen Fällen zu erheblichen Leistungssteigerungen führen.

Verwandte Themen