2010-11-26 9 views
11

Ich lese Hadoop: Die definitive Anleitung von Tom White. In Kapitel 13.6 "HBase vs RDMS" sagte er, dass, wenn Sie viele Daten haben, selbst einfache Abfragen wie 10 neue Elemente extrem teuer sind und sie mit Python und PL/SQL neu geschrieben werden mussten.Sind RDBMS so schlecht, wie in Hadoop beschrieben: Der definitive Leitfaden?

Er gibt die folgende Abfrage als Beispiel:

SELECT id, stamp, type FROM streams 
WHERE type IN ('type1','type2','type3','type4',...,'typeN') 
ORDER BY stamp DESC LIMIT 10 OFFSET 0; 

Und sagt: „ein RDBMS Anfrageplaner behandelt diese Abfrage wie folgt:

MERGE (
    SELECT id, stamp, type FROM streams 
    WHERE type = 'type1' ORDER BY stamp DESC, 
    ..., 
    SELECT id, stamp, type FROM streams 
    WHERE type = 'typeK' ORDER BY stamp DESC 
) ORDER BY stamp DESC LIMIT 10 OFFSET 0; 

Das Problem hier ist, dass wir nach nur die oberen 10 IDs, aber die Abfrage Planer tatsächlich eine gesamte Merge materialisiert und dann begrenzt auf die Ende .... Wir gingen tatsächlich so weit wie , um ein benutzerdefiniertes PL/Python-Skript zu schreiben, das einen Heapsort ausführte. ... In fast allen Fällen übertraf diese die native SQL-Implementierung und die Strategie der Anfrageplaner ...

Erwartet perforamnce und expermiental Ergebnisse

Ich konnte den Datensatz nicht vorstellen, das wird solche probleme verursachen, dass du pl/python schreiben musst, um so einfache abfrage zu machen. Also habe ich eine Weile über dieses Problem gespielt und kam zu folgenden Beobachtungen:

Die Leistung einer solchen Abfrage wird durch O (KlogN) begrenzt. Weil es übersetzt werden kann, um so etwas wie folgt:

SELECT * FROM (
    SELECT id, stamp, type FROM streams 
    WHERE type = 'type1' ORDER BY stamp DESC LIMIT 10, 
    UNION 
    ..., 
    SELECT id, stamp, type FROM streams 
    WHERE type = 'typeK' ORDER BY stamp DESC LIMIT 10 
) t ORDER BY stamp DESC LIMIT 10; 

(beachten Sie die ‚LIMIT 10‘ bei jeder Abfrage BTW weiß ich, dass ich nicht begrenzen und Gewerkschaften Reihenfolge kann, aber ich habe Einwickeln wählt abgezogen. aus Gründen der Lesbarkeit)

Jede Unterabfrage sollte so schnell laufen wie das Finden der richtigen Position in einem Index O (logN) und das Zurückgeben von 10 Elementen. Wenn wir das K mal wiederholen, erhalten wir O (KlogN).

Und auch wenn der Abfrageplaner so schlecht ist, dass er die erste Abfrage nicht optimieren kann, können wir ihn immer in die Abfrage mit Unionen übersetzen und die gewünschte Leistung erhalten, ohne etwas in pl/python zu schreiben.

Um meine Berechnungen zu überprüfen, habe ich die Abfragen über einem PostgreSQL mit 9.000.000 Testaufzeichnungen ausgeführt. Die Ergebnisse bestätigten meine Erwartungen, dass beide Anfragen für die erste Anfrage 100 ms und für die zweite 300 ms waren.

Wenn also die Abfrage in 100ms für 9.000.000 (logn = 23) Datensätze ausgeführt wird, dann sollte sie für 9.000.000.000 (logn = 33) Datensätze in 140ms laufen.

Fragen

  • Sehen Sie irgendwelche Mängel in oben Argumentation?
  • Können Sie sich einen Datensatz vorstellen, in dem Sie solche Abfragen wie oben in pl/python schreiben müssten?
  • Sehen Sie eine Situation, in der eine solche Abfrage in O (K log n) nicht funktionieren würde?
+0

Nein, sind sie nicht. Welche Datenbank fragt einmal für jedes Element in einem Filter eines Feldes eine vollständige Tabelle ab, führt alle Datensätze zusammen, ordnet sie an und führt dann die Begrenzung am Ende aus? – MkV

Antwort

6

Ihre Behauptung, dass ein RDMBS-Abfrageplaner diese Lösung zu der Abfrage führt, ist zumindest für Postgresql 9.0 falsch, und ich sollte mir das auch für andere Plattformen vorstellen. Ich habe einen schnellen Test mit einer ähnlichen Abfrage:

explain select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by client_attribute_id desc limit 10; 

                 QUERY PLAN 
----------------------------------------------------------------------------------------------------------------------- 
Limit (cost=0.00..0.93 rows=10 width=85) 
    -> Index Scan Backward using client_attribute_pkey on client_attribute (cost=0.00..15516.47 rows=167234 width=85) 
     Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[])) 
(3 rows) 

Hier client_attribute_id ist indiziert, so dass es genau das tut, wie desired- zurück durch den Index geht, wendet den Filter und stoppt, wenn der Ausgang der Grenze trifft.

Wenn die Bestellung Spalte nicht indiziert ist, eine Tabellensuche und Sortierung ist requierd, aber nur eine Tabelle scannen:

explain analyze select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by updated desc limit 10; 

                   QUERY PLAN 
--------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=13647.00..13647.03 rows=10 width=85) (actual time=180.961..180.964 rows=10 loops=1) 
    -> Sort (cost=13647.00..14065.09 rows=167234 width=85) (actual time=180.960..180.961 rows=10 loops=1) 
     Sort Key: updated 
     Sort Method: top-N heapsort Memory: 26kB 
     -> Seq Scan on client_attribute (cost=0.00..10033.14 rows=167234 width=85) (actual time=0.010..106.791 rows=208325 loops=1) 
       Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[])) 

Dieser verwendet eine Heapsort die Top 10 Ergebnisse durch den Verlauf des sequentiellen Scan zu halten , die genau wie die Lösung klingt, die sie selbst geschrieben haben.

4

Ich glaube nicht, dass Tom White sagt, dass relationale Datenbanken "schlecht" sind; Sie sind nicht optimal für nicht-relationale, nicht-set-basierte Daten.

Es ist seit langem bekannt, dass Deep-Object-Graphen sich nicht gut für relationale Datenbanken eignen. Sie finden sich typischerweise in Problemen wie CAD-Darstellungen geometrischer Daten, bei denen Baugruppen aus Baugruppen von Bauteilgruppen bestehen. Die Referenzketten sind in der Tat sehr lang.

Objekt- und Graph-Datenbanken waren die Lösungen für diese Art von Problemen, seit ich sie in den frühen 90er Jahren kannte.

Relationale Datenbanken sind hervorragend für relationale, Set-basierte Daten. Aber alle Daten fallen nicht in diese Kategorie. Deshalb gewinnt NoSQL mehr und mehr an Bedeutung.

Ich denke, das ist, was das Beispiel zitiert, das Sie anführen.

+3

Was er zu sagen scheint, ist, dass Abfrageplaner in RDBMSes schlecht sind. Es ist besser in Python zu schreiben, aber ein erfundenes Beispiel zu verwenden, das nicht repräsentativ für tatsächliche Abfrageplaner ist, die von tatsächlichen RDBMS verwendet werden. – MkV

1

RDBMS ist für die Abfragen, an die Sie nicht gedacht haben. Sobald Sie genau wissen, was Sie wollen, können Sie dann die optimale Lösung anwenden.

1

Mit SQL oder NoSQL wird die Leistung schrecklich, wenn Sie Ihre Abfragen in der falschen Weise entwerfen.

Ich würde dieses Beispiel beheben, indem Sie der Where-Klausel eine Überprüfung des Zeitstempels hinzufügen. Wenn Sie viele Daten haben, können Sie wahrscheinlich davon ausgehen, dass die letzten 10 Einträge aus der letzten Minute stammen - warum also versuchen Sie, alles aus dem letzten Monat zu lesen und zu sortieren?

Ich könnte genauso gut das gleiche Beispiel ersinnen, um NoSQL schlecht aussehen zu lassen, indem man behauptet, dass man Datensätze nur nach ID finden kann. Man muss den gesamten Datensatz laden, um den benötigten Datensatz zu finden Richten Sie verschiedene sekundäre/benutzerdefinierte Indizes ein, mit denen Sie die SQL-Leistung für die relevanten Abfragen verbessern können.