Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie implementiert man die Suche nach 2 verschiedenen Tabellendaten?

Hier sind ein paar "Spielregeln", die Sie beachten müssen, um dieses Problem zu lösen. Sie kennen diese wahrscheinlich bereits, aber wenn Sie sie klar formulieren, können Sie sie anderen Lesern bestätigen.

  • Alle Indizes in MySQL können nur auf Spalten in einer einzigen Basistabelle verweisen. Sie können keinen Volltextindex erstellen, der mehrere Tabellen indiziert.
  • Sie können keine Indizes für Ansichten definieren, sondern nur Basistabellen.
  • Ein MATCH() Eine Abfrage für einen Volltextindex muss mit allen Spalten im Volltextindex in der im Index deklarierten Reihenfolge übereinstimmen.

Ich würde eine dritte Tabelle erstellen, um den Inhalt zu speichern, den Sie indizieren möchten. Dieser Inhalt muss nicht redundant gespeichert werden – speichern Sie ihn ausschließlich in der dritten Tabelle. Dies leiht sich ein Konzept einer "gemeinsamen Superklasse" aus dem objektorientierten Design (soweit wir es auf das RDBMS-Design anwenden können).

CREATE TABLE Searchable (
  `id` SERIAL PRIMARY KEY,
  `title` varchar(100) default NULL,
  `description` text,
  `keywords` text,
  `url` varchar(255) default '',
  FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shopitems` (
  `id` INT UNSIGNED NOT NULL,
  `ShopID` INT UNSIGNED NOT NULL,
  `ImageID` INT UNSIGNED NOT NULL,
  `pricing` varchar(45) NOT NULL,
  `datetime_created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shops` (
  `id` INT UNSIGNED NOT NULL,
  `owner_id` varchar(255) default NULL,
  `datetime_created` datetime default NULL,
  `created_by` varchar(255) default NULL,
  `datetime_modified` datetime default NULL,
  `modified_by` varchar(255) default NULL,
  `overall_rating_avg` decimal(4,2) default '0.00',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Beachten Sie, dass die einzige Tabelle mit einem Auto-Increment-Schlüssel jetzt Searchable ist . Die Tabellen shops und shopitems Verwenden Sie einen Schlüssel mit einem kompatiblen Datentyp, aber nicht mit automatischer Erhöhung. Sie müssen also eine Zeile in Searchable erstellen um die id zu generieren Wert, bevor Sie die entsprechende Zeile in einem der beiden shops erstellen können oder shopitems .

Ich habe FOREIGN KEY hinzugefügt Deklarationen zu Veranschaulichungszwecken, obwohl MyISAM diese Einschränkungen stillschweigend ignoriert (und Sie bereits wissen, dass Sie MyISAM verwenden müssen, um Unterstützung für die Volltextindizierung zu haben).

Jetzt können Sie die Textinhalte beider shops durchsuchen und shopitems in einer einzigen Abfrage mit einem einzigen Volltextindex:

SELECT S.*, sh.*, si.*,
  MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;

Natürlich für eine bestimmte Zeile in Searchable nur eine Tabelle sollte übereinstimmen, entweder Shops oder Shopitems, und diese Tabellen haben unterschiedliche Spalten. Also entweder sh.* oder si.* wird im Ergebnis NULL sein. Es liegt an Ihnen, die Ausgabe in Ihrer Anwendung zu formatieren.

Ein paar andere Antworten haben vorgeschlagen, Sphinx-Suche zu verwenden . Dies ist eine weitere Technologie, die MySQL ergänzt und eine ausgefeiltere Volltextsuchfunktion hinzufügt. Es hat eine hervorragende Leistung für Abfragen, sodass einige Leute davon ziemlich verzaubert sind.

Das Erstellen von Indizes und insbesondere das schrittweise Hinzufügen zu einem Index ist jedoch teuer. Tatsächlich ist die Aktualisierung eines Sphinx-Suchindex so kostspielig, dass die empfohlene Lösung darin besteht, einen Index für ältere, archivierte Daten und einen weiteren kleineren Index für neuere Daten zu erstellen, die mit größerer Wahrscheinlichkeit aktualisiert werden. Dann muss jede Suche zwei Abfragen gegen die zwei separaten Indizes ausführen. Und wenn sich Ihre Daten nicht von Natur aus für das Muster der Unveränderlichkeit älterer Daten eignen, können Sie diesen Trick möglicherweise sowieso nicht nutzen.

Zu Ihrem Kommentar:Hier ist ein Auszug aus der Sphinx Search-Dokumentation über Live-Updates eines Indexes:

Da es kostspielig ist, einen Sphinx-Suchindex zu aktualisieren, besteht die Idee darin, den Index, den Sie aktualisieren, so klein wie möglich zu machen. Damit sich nur die neuesten Forenbeiträge (in ihrem Beispiel) ändern, während sich der größere Verlauf der archivierten Forenbeiträge nie ändert, erstellen Sie für diese Sammlung einmalig einen zweiten, größeren Index. Wenn Sie eine Suche durchführen möchten, müssen Sie natürlich beide Indizes abfragen.

In regelmäßigen Abständen, sagen wir einmal pro Woche, würden die "neuesten" Forennachrichten als "archiviert" betrachtet und Sie müssten den aktuellen Index für die letzten Beiträge mit dem archivierten Index zusammenführen und den kleineren Index von vorne beginnen. Sie weisen darauf hin, dass das Zusammenführen von zwei Sphinx Search-Indizes effizienter ist als die Neuindizierung nach einer Aktualisierung der Daten.

Aber mein Punkt ist, dass nicht jeder Datensatz von Natur aus in das Muster eines archivierten Datensatzes fällt, der sich nie ändert, im Gegensatz zu aktuellen Daten, die häufig aktualisiert werden.

Nehmen Sie zum Beispiel Ihre Datenbank:Sie haben Shops und Shopartikel. Wie können Sie diese in Zeilen aufteilen, die sich nie ändern, im Gegensatz zu neuen Zeilen? Alle Shops oder Produkte im Katalog sollten ihre Beschreibung aktualisieren können. Aber da das jedes Mal, wenn Sie eine Änderung vornehmen, den gesamten Sphinx-Suchindex neu erstellen müsste, wird dies zu einem sehr teuren Vorgang. Vielleicht würden Sie Änderungen in eine Warteschlange stellen und sie in einem Stapel anwenden, wobei Sie den Index einmal pro Woche neu erstellen. Aber versuchen Sie, den Ladenverkäufern zu erklären, warum eine geringfügige Änderung ihrer Ladenbeschreibung erst am Sonntagabend wirksam wird.