2016-08-01 17 views
1

Ich versuche, eine linke Verknüpfung zwischen zwei Tabellen in einer PostgreSQL-Datenbank zu tun und es dauert etwa 14 Minuten zu laufen. Aus bestehenden SO-Posts scheint diese Art von Joins in der Größenordnung von Sekunden zu liegen. Daher würde ich gerne wissen, wie man die Leistung dieses Joins verbessert. Ich betreibe 64-bit auf einer Windows 8 Maschine w/8 GB RAM, mit pgAdmin III. Die Tabellenstrukturen sind wie folgt:Verbessern der Leistung für einfache linke Join in PostgreSQL

Tabelle A: "parcels_qtr":

Paket (Text) | Jahr (int) | qtr (Text) | lpid (pk, Text) |

Hat 15,5 Millionen Zeilen, jede Spalte ist indiziert und "lpid" ist der Primärschlüssel. Ich führte diesen Tisch auch durch einen Standard-Vakuumprozess.

Tabelle B: "postalvac_qtr":

Paket (Text) | Jahr (int) | qtr (Text) | lpid (pk, Text) | vacCountY (int) |

Hat 618.000 Datensätze, alle Felder außer "vacCountY" sind indiziert und "lpid" ist der Primärschlüssel. Dies hat auch einen Standard-Vakuumprozess durchlaufen.

Wenn die Datenausgabe ausgeführt wird, dauert es etwa 14 Minuten. Beim Laufen mit explain (analyze, buffers) dauert es etwas mehr als eine Minute. Erste Frage - Ist dieser Leistungsunterschied vollständig auf das Drucken der Daten zurückzuführen oder läuft hier etwas anderes?

Und zweite Frage, kann ich diese Laufzeit auf ein paar Sekunden runter?

Hier ist meine SQL-Code:

EXPLAIN (ANALYZE, BUFFERS) 
select a.parcel, 
    a.lpid, 
    a.yr, 
    a.qtr, 
    b."vacCountY" 
from parcels_qtr as a 
left join postalvac_qtr as b 
on a.lpid = b.lpid; 

Und hier sind die Ergebnisse meiner Aussage erklären: https://explain.depesz.com/s/uKkK

ich postgreSQL ziemlich neu bin so Geduld und Erklärungen wäre sehr dankbar!

+0

'Jahr (int) | qtr (Text) 'das sieht aus wie Jahr und Quartal, warum nicht stattdessen ein Datumsfeld verwenden (das Textfeld verlieren) und date_trunc() darauf ausführen? 'Alle Felder außer" vacCountY "sind indiziert und" lpid "ist der Primärschlüssel. Bitte lernen Sie etwas über Datenmodellierung, eine Datenbank soll keine Tabellenkalkulation mit Indizes sein. – joop

+0

Hey @joop, danke für die Tipps zum Datumsfeld. Ich werde es versuchen. Ich habe Indizes für diese anderen Felder hinzugefügt, weil sie möglicherweise an Joins in zukünftigen Abfragen beteiligt sind. Welche Ressourcen schlage ich in Bezug auf die Datenmodellierung vor? Gibt es ein bestimmtes Buch oder Tutorial, das Sie im Sinn hatten? – Parker

+0

Es ist nicht klar aus Ihrer Frage, was Ihre Tabellen bedeuten *. Die parcels_qtr sieht aus wie eine Voraggregation eines Zählfeldes "vacCountY". Was ist lpid (welches als Join-Feld verwendet wird). und was heißt 'Paket (Text) | Jahr (int) | qtr (Text) | lpid (pk, Text) | vacCountY (int) | 'gemein. Die meisten Leute hier bevorzugen einfache sql DDL-Tabellendefinitionen zu Ihrer klingonischen Notation, IMHP. – wildplasser

Antwort

4

Sie bitten die DB, einiges zu tun. Einfach mal auf dem Plan erklären, es ist:

  1. liest in einer ganzen Tabelle (postalvac_qtr)
  2. ein Hash-basierte baut auf lpid
  3. liest in einem ganzen anderen, viel größeren, Tisch (parcels_qtr)
  4. Hash jeder der 15MM lpid s, und sie an den bestehenden Hash-Tabelle

Wie groß sind diese Tabellen überein? Sie können dies durch die Ausgabe von:

SELECT pg_size_pretty(pg_relation_size('parcels_qtr')); 

mir fast sicher bin, dass diese Hashverknüpfung auf der Festplatte aus verschütten, und die Art, wie es strukturiert ist („Gib mir all der Daten aus beiden Tabellen“), es wird nicht möglich sein.

Die Indizes helfen nicht und können nicht. Solange Sie nach der Gesamtheit einer Tabelle fragen, würde die Verwendung eines Indexes die Dinge nur verlangsamen - postgres muss die gesamte Tabelle trotzdem durchqueren, so dass es auch einen sequentiellen Scan geben könnte.

Warum die Abfrage hat eine andere Leistung als die explain analyze, ich vermute, dass Sie richtig sind. Eine Kombination von 1- Senden von 15 Millionen Zeilen an Ihren Client und 2- versuchen, es anzuzeigen, wird eine erhebliche Verlangsamung über die eigentliche Abfrage hinaus verursachen.

Also, was können Sie dagegen tun?

Erstens, was versucht diese Abfrage zu tun? Wie oft möchten Sie alle der Daten in diesen beiden Tabellen vollständig ungefiltert greifen? Wenn es sehr häufig vorkommt, sollten Sie in Betracht ziehen, in die Phase der Anforderungen zurückzukehren und einen anderen Weg zu finden, um diesem Bedarf zu entsprechen (z. B. wäre es sinnvoll, stattdessen alle Daten für ein bestimmtes Jahr und Quartal zu erfassen). Wenn es ungewöhnlich ist (sagen wir, ein täglicher Export), dann könnten 1-14 Minuten in Ordnung sein.

Zweitens sollten Sie sicherstellen, dass Ihre Tabellen nicht aufgebläht sind. Wenn Sie bemerkenswerte update oder Traffic auf Ihren Tischen erfahren, kann das im Laufe der Zeit wachsen. Der Autovacuum-Daemon hilft dabei, aber gelegentlich kann auch die Ausgabe eines vacuum full helfen.

Drittens können Sie versuchen, Ihre DB-Konfiguration zu tunen. In postgresql.conf gibt es Parameter für Dinge wie die erwartete Menge an RAM, die Ihr Server für den Plattencache verwenden kann, und die Menge an RAM, die der Server zum Sortieren oder Verbinden verwenden kann (bevor es auf die Festplatte ausläuft). Wenn Sie mit diesen Parametern experimentieren, können Sie möglicherweise die Geschwindigkeit verbessern.

Viertens möchten Sie möglicherweise Ihr Schema erneut besuchen. Wollen Sie Jahr und Quartal als zwei separate Spalten, oder wären Sie mit einer einzigen Spalte des Typs date besser dran? Möchten Sie einen Schlüssel text, oder würden Sie mit einem bigint (entweder seriell oder abgeleitet von der Spalte text) besser sein, die wahrscheinlich schneller beitreten wird? Werden die Felder parcel, yr und qtr tatsächlich in beiden Tabellen benötigt, oder handelt es sich um doppelte Daten in einer Tabelle?

Wie auch immer, ich hoffe, das hilft.

+0

Wow, das ist sehr hilfreich, danke, dass du dir die Zeit genommen hast, es zu erklären. Was Sie bei einem Table Scan erwähnt haben, ist sehr sinnvoll. Ich denke, das wäre eine ziemlich seltene Aufgabe, also haben Sie vielleicht Recht, 14 Minuten sind nicht das Ende der Welt.Es ist gut zu wissen, dass das, was ich versuche, keine unverschämte Laufzeit ist. Ich überprüfe die Parameter in der DB-Konfiguration und spiele mit Datentypen, wie Sie und @joop vorgeschlagen haben. Viel zu probieren hier, danke !! – Parker

+0

Parker, da Sie neu hier sind, kann ich darauf hinweisen, dass die bevorzugte Art, hier "Danke" zu sagen, darin besteht, gute Fragen und hilfreiche Antworten zu wählen (sobald Sie genug Reputation haben) und die hilfreichsten zu akzeptieren Beantworten Sie jede Frage, die Ihnen auch einen kleinen Auftrieb gibt. – e4c5

+0

Danke allen! Antwort angenommen! Das Vermeiden der Anzeige der Daten war wahrscheinlich die größte Hilfe, ebenso wie die Verwendung geeigneterer Datentypen. – Parker