2012-04-07 5 views
59

Ich bin kürzlich von Postgres zu Solr gewechselt und habe in unseren Abfragen eine ca. 50-fache Beschleunigung gesehen. Die Abfragen, die wir ausführen, umfassen mehrere Bereiche und unsere Daten sind Fahrzeuglisten. Zum Beispiel: „Alle Fahrzeuge gebrauchten Autos < 50.000, $ 5.000 < Preis < $ 10.000, machen = Mazda ...“Warum ist Solr so viel schneller als Postgres?

Ich habe Indizes auf allen relevanten Spalten in Postgres, so sollte es ein ziemlich fairer Vergleich sein. Ich schaue mir den Abfrageplan in Postgres an, obwohl er immer noch nur einen einzigen Index verwendet und dann gescannt hat (ich nehme an, weil er nicht alle verschiedenen Indizes nutzen konnte).

Wie ich es verstehe, verwenden Postgres und Solr vage ähnliche Datenstrukturen (B-Bäume), und sie beide Daten im Speicher zwischenspeichern. Ich frage mich also, woher solch ein großer Leistungsunterschied kommt.

Welche Unterschiede in der Architektur würde dies erklären?

+3

Haben Sie Postgres Volltextsuche oder einfache 'LIKE' Anfragen verwendet? –

+0

Das relationale Modell war nie dazu gedacht, bei hässlichen Fragen wie "Gib mir all die Leute, die an einem Mittwoch geboren wurden und zwischen 2003 und 2005 ein rotes Auto besaßen", gut zu funktionieren. Dafür gibt es Suchmaschinen (wie Lucene). Indizes helfen manchmal, Speichereinstellungen helfen immer. – wildplasser

+1

Ich bin ein wenig verwirrt durch Ihre Frage, also frage ich hier: http://dba.stackexchange.com/questions/34014/using-solr-lucene-for-searching-non-text-tables Will/can Solr/Lucene Suchvorgänge sind schneller als PostgreSQL, auch wenn keine Volltextsuche durchgeführt wird? – alfonx

Antwort

120

Zunächst verwendet Solr keine B-Bäume. Ein Lucene-Index (die zugrunde liegende Bibliothek, die von Solr verwendet wird) besteht aus einer schreibgeschützten segments. Für jedes Segment unterhält Lucene ein Begriffslexikon, das aus der Liste der Begriffe besteht, die im Segment erscheinen, lexikographisch sortiert. Nachschlagen eines Begriffs in diesem Begriff Wörterbuch erfolgt mit einer binären Suche, so dass die Kosten für eine Single-Term-Lookup O(log(t)) ist, wobei t die Anzahl der Begriffe ist. Im Gegensatz dazu kostet die Verwendung des Index eines Standard-RDBMS O(log(d)), wobei d die Anzahl der Dokumente ist. Wenn viele Dokumente für ein Feld den gleichen Wert haben, kann dies ein großer Gewinn sein.

Darüber hinaus Unterstützung Lucene Committer Uwe Schindler für sehr performant numeric range queries vor ein paar Jahren. Für jeden Wert einer numeric field speichert Lucene mehrere Werte mit unterschiedlichen Genauigkeiten. Dadurch kann Lucene Bereichsabfragen sehr effizient ausführen. Da Ihr Anwendungsfall häufig numerische Bereichsabfragen nutzt, könnte dies erklären, warum Solr so viel schneller ist. (Für weitere Informationen, lesen Sie die Javadocs, die sehr interessant sind und Links zu relevanten Forschungsarbeiten geben.)

Aber Solr kann dies nur tun, weil es nicht alle Einschränkungen hat, die ein RDBMS hat. Zum Beispiel ist Solr sehr schlecht darin, ein einzelnes Dokument zu einem Zeitpunkt zu aktualisieren (es bevorzugt Batch-Aktualisierungen).

+4

Große Antwort (der erste Absatz) +1. – Yavar

+2

Obwohl ich hier etwas zu sagen habe. Wenn Sie sagen, dass "Lucene ein Begriffswörterbuch verwaltet, das aus der Liste der Begriffe besteht, die in dem Segment angezeigt werden, lexikographisch sortiert". Wenn also die Begriffe lexikographisch sortiert sind und die Zeit o (log t) benötigt wird (Binärsuche), bedeutet dies, dass die Begriffe in einem Array gespeichert sind. Ist das richtig (ich meine, wie Sie eine ausgewogene Baumstruktur für die Speicherung von Indizes abgelehnt und Hash-Tabelle kann nicht direkt sortierte Indizes speichern, so dass wir nur mit einem 2D-Array (mit Begriff, Zeiger auf Postings Liste als seine Elemente) Struktur, auf der binären Suche wird fortgesetzt) ​​ – Yavar

+3

Eine andere Sache, die hier hinzugefügt wird, ist, auch wenn der Lucene Index kein BTree ist, es ist jedoch ein invertierter Index (wie der Großteil der Suchmaschine). Ihre Antwort kam mir jedoch als etwas Neues. Da ich erwartet habe, dass eine Balanced Tree-Struktur Terme speichert (In diesem Fall wäre die Suche auch log (t) und jeder Knoten enthält auch einen Zeiger auf Buchungslisten. Mit Balance Trees könnten wir sogar lexikographisch sortierte Terme pflegen. – Yavar

1

Bitte lesen Sie this und this.

Solr (Lucene) erstellt eine inverted index, wo Daten schneller abgerufen werden. I read, dass PostgreSQL hat auch ähnliche Einrichtung, aber nicht sicher, ob Sie das verwendet hatten.

Die Leistungsunterschiede, die Sie beobachtet haben, können auch auf "was wird gesucht?", "Was sind die Benutzerabfragen?"

+0

Danke!Das waren sehr interessant. Ich habe auf etwas technischeres gehofft. Wie eine Architekturübersicht von Solr oder so ähnlich. – cberner

+0

@Tejas: Sogar Datenbanken können invertierte Indizes erzeugen. Was hält sie davon ab, invertierte Indizes zu erstellen? – Yavar

+0

Yavar: Ich habe nicht gesagt, dass Datenbanken keine invertierten Indizes erstellen können. Tatsächlich habe ich in der zweiten Zeile darauf hingewiesen, dass PostgreSQL einen GIN-invertierten Index verwendet. Es gibt einen anderen Typ: GiST (generalisierter Suchbaum) -basierter Index in PostgreSQL, der langsamer als GIN ist. Der tatsächliche von @cberner verwendete Indextyp ist ein Faktor für die geringe Leistung von PostgreSQL. –

5

Solr wurde primär für die Suche von Daten entwickelt, nicht für die Speicherung. Dies ermöglicht es, einen Großteil der von einem RDMS benötigten Funktionalität zu verwerfen. Es konzentriert sich also (oder vielmehr lucene) auf die reine Indizierung von Daten.

Wie Sie sicher festgestellt haben, ermöglicht Solr das Suchen und Abrufen von Daten aus dem Index. Es ist die letztere (optionale) Fähigkeit, die zu der natürlichen Frage führt ... "Kann ich Solr als Datenbank verwenden?"

Die Antwort ist ein eingeschränktes Ja, und ich verweise Sie auf die folgenden:

Meine persönliche Meinung ist, dass Solr beste Gedanke ist von als ein durchsuchbarer Cache zwischen meiner Anwendung und den in meiner Datenbank gemasterten Daten. So erhalte ich das Beste aus beiden Welten.

6

Der größte Unterschied ist, dass ein Lucene/Solr-Index wie eine Single-Table-Datenbank ohne Unterstützung für relationale Abfragen (JOINs) ist. Denken Sie daran, dass ein Index normalerweise nur dort vorhanden ist, um die Suche zu unterstützen und nicht die primäre Quelle der Daten zu sein. Ihre Datenbank kann also in der "dritten Normalform" sein, aber der Index wird vollständig de-normalisiert und enthält meistens nur die Daten, die gesucht werden müssen.

Ein weiterer möglicher Grund ist, dass Datenbanken im Allgemeinen unter interner Fragmentierung leiden und bei großen Anfragen zu viele halb-zufällige E/A-Aufgaben ausführen müssen.

Was bedeutet das zum Beispiel, wenn man die Indexarchitektur einer Datenbank betrachtet, führt die Abfrage zu den Indizes, die wiederum zu den Daten führen. Wenn die wiederherzustellenden Daten weit verbreitet sind, wird das Ergebnis lange dauern und das scheint in Datenbanken der Fall zu sein.

35

Sie haben nicht wirklich viel darüber gesagt, was Sie getan haben, um Ihre PostgreSQL-Instanz oder Ihre Abfragen zu optimieren. Es ist nicht ungewöhnlich, dass Sie eine PostgreSQL-Abfrage um 50x beschleunigen, indem Sie Ihre Abfrage in einem Format optimieren und/oder neu formatieren, das für eine bessere Optimierung sorgt.

Gerade diese Woche gab es einen Bericht bei der Arbeit, den jemand mit Java und mehreren Abfragen auf eine Weise geschrieben hatte, die, je nachdem, wie weit sie in vier Stunden gekommen war, ungefähr einen Monat in Anspruch nehmen würde. (Es musste fünf verschiedene Tabellen mit jeweils Hunderten von Millionen Zeilen durchlaufen.) Ich schrieb es mit mehreren CTEs und einer Fensterfunktion um, so dass es in weniger als zehn Minuten lief und die gewünschten Ergebnisse direkt aus der Abfrage erzeugte. Das ist eine 4400-fache Beschleunigung.

Vielleicht ist die beste Antwort auf Ihre Frage hat nichts mit den technischen Einzelheiten zu tun, wie sucht in jedem Produkt durchgeführt werden kann, sondern mehr mit einfacher Bedienung für Ihren speziellen Anwendungsfall zu tun. Es war klar, dass Sie den schnellen Weg, mit Solr zu suchen, mit weniger Schwierigkeiten finden konnten als PostgreSQL, und es kann zu nichts anderem kommen.

Ich bin ein kurzes Beispiel, wie Text sucht nach mehreren Kriterien in PostgreSQL getan werden kann, und wie ein paar kleine Optimierungen einen großen Leistungsunterschied machen können. Um es schnell und einfach zu halten, führe ich einfach Krieg und Frieden in Textform in eine Testdatenbank, wobei jedes "Dokument" eine einzelne Textzeile ist. Ähnliche Techniken können für beliebige Felder mit den Spalten hstore oder JSON verwendet werden, wenn die Daten lose definiert sein müssen. Wenn separate Spalten mit eigenen Indizes vorhanden sind, sind die Vorteile bei der Verwendung von Indizes wesentlich größer.

-- Create the table. 
-- In reality, I would probably make tsv NOT NULL, 
-- but I'm keeping the example simple... 
CREATE TABLE war_and_peace 
    (
    lineno serial PRIMARY KEY, 
    linetext text NOT NULL, 
    tsv tsvector 
); 

-- Load from downloaded data into database. 
COPY war_and_peace (linetext) 
    FROM '/home/kgrittn/Downloads/war-and-peace.txt'; 

-- "Digest" data to lexemes. 
UPDATE war_and_peace 
    SET tsv = to_tsvector('english', linetext); 

-- Index the lexemes using GiST. 
-- To use GIN just replace "gist" below with "gin". 
CREATE INDEX war_and_peace_tsv 
    ON war_and_peace 
    USING gist (tsv); 

-- Make sure the database has statistics. 
VACUUM ANALYZE war_and_peace; 

Einmal für die Indizierung einrichten, zeigen, dass ich ein paar Recherchen mit Zeilenanzahl und Timings mit beiden Arten von Indizes:

-- Find lines with "gentlemen". 
EXPLAIN ANALYZE 
SELECT * FROM war_and_peace 
    WHERE tsv @@ to_tsquery('english', 'gentlemen'); 

84 Zeilen, Kern: 2,006 ms, Gin: 0,194 ms

-- Find lines with "ladies". 
EXPLAIN ANALYZE 
SELECT * FROM war_and_peace 
    WHERE tsv @@ to_tsquery('english', 'ladies'); 

184 Zeilen, gist: 3.549 ms, Gin: 0.328 ms

-- Find lines with "ladies" and "gentlemen". 
EXPLAIN ANALYZE 
SELECT * FROM war_and_peace 
    WHERE tsv @@ to_tsquery('english', 'ladies & gentlemen'); 

1 Zeile, Kern: 0,971 ms, Gin: 0,104 ms

Da nun der GIN-Index etwa 10-mal schneller als der GiST Index war fragen Sie sich vielleicht, warum jemand GiST für die Indizierung verwenden würde, Textdaten. Die Antwort lautet, dass GiST im Allgemeinen schneller zu warten ist. Wenn Ihre Textdaten also sehr unbeständig sind, könnte der GiST-Index bei einer allgemeinen Auslastung gewinnen, während der GIN-Index gewinnen würde, wenn Sie nur an der Suchzeit oder an einer Lesearbeitslast interessiert sind.

Ohne den Index nehmen die obigen Abfragen zwischen 17,943 ms und 23,397 ms, da sie die gesamte Tabelle scannen und nach einer Übereinstimmung in jeder Zeile suchen müssen.

Die GIN-indizierte Suche nach Zeilen mit "Damen" und "Gentlemen" ist über 172 mal schneller als ein Tabellenscan in genau derselben Datenbank. Offensichtlich wären die Vorteile der Indexierung bei größeren Dokumenten dramatischer als bei diesem Test.

Das Setup ist natürlich eine einmalige Sache. Mit einem Auslöser, um die Spalte tsv beizubehalten, wären alle vorgenommenen Änderungen sofort durchsuchbar, ohne das Setup zu wiederholen.

Mit einer langsamen PostgreSQL-Abfrage, wenn Sie die Tabellenstruktur (einschließlich Indizes), die Problemabfrage und die Ausgabe von EXPLAIN ANALYZE Ihrer Abfrage zeigen, kann jemand fast immer das Problem erkennen und vorschlagen, wie es ausgeführt wird schneller.


UPDATE (9. Dezember '16)

Ich habe nicht erwähnt, was ich verwenden, um die vorherigen Zeitpunkt zu bekommen, aber auf der Grundlage des Zeitpunkt wäre es wahrscheinlich die Version 9.2 wichtigsten gewesen sein. Ich bin gerade über diesen alten Thread gestolpert und habe es auf der gleichen Hardware mit Version 9.6.1 erneut versucht, um zu sehen, ob irgendeine der dazwischenliegenden Performance-Einstellungen dieses Beispiel unterstützt. Die Abfragen für nur ein Argument haben nur um etwa 2% in der Leistung zugenommen, aber die Suche nach Linien mit beiden "Damen" und "Gentlemen" über die doppelte Geschwindigkeit auf 0,053 ms (dh 53 Mikrosekunden) bei Verwendung der GIN (invertiert) Index.

+4

Beachten Sie, dass GiST nicht mehr so ​​viel schneller zu warten ist, vgl. http://blog.pgaddict.com/posts/performance-since-postgresql-7-4-to-9-4-fulltext – ArtemGr