2016-04-06 8 views
1

Ich habe eine Master/Detail-Tabelle Situation. Für jeden Eintrag am Stammtisch habe ich Dutzende an der Detailtabelle.Patial Index basiert auf Daten der zweiten Tabelle

Können sagen, das ist meine Tabellen sind:

+----------------------- 
| Master 
+----------------------- 
| master_key integer, 
| insert_date timestamp 
+----------------------- 

+----------------------- 
| Detail 
+----------------------- 
| detail_key integer, 
| master_key integer 
| quantity numeric 
| amount numeric 
+----------------------- 

Und meine am meisten verwendete Abfrage ist so etwas wie

SELECT extract(year from insert_date) AS Insert_Year, extract(month from insert_date) AS Insert_Month, sum(quantity) AS Quantity, sum(amount) AS Amount 
FROM Master, Detail 
WHERE (amount not null) and (insert_date <= '2016-12-31') and (insert_date >= '2015-01-01') and (Detail.master_key=Master.master_key) 
GROUP BY Insert_Year, Insert_Month 
ORDER BY Insert_Year ASC, Insert_Month ASC; 

Diese Abfrage zu verlangsamen wird, weil es Tonnen von Daten für viele Jahre ist in beiden Tabellen .

Natürlich habe ich Indizes an beiden Tabellen und EXPLAIN ANALYZE sagt mir, dass der INDEX-Scan-Modus als 80% der Loch-Ausführungszeit dauert.

"Sort (cost=44013.52..44013.53 rows=1 width=19) (actual time=17073.129..17073.129 rows=16 loops=1)" 
" Sort Key: (date_part('year'::text, master.insert_date)), (date_part('month'::text, master.insert_date))" 
" Sort Method: quicksort Memory: 26kB" 
" -> HashAggregate (cost=44013.49..44013.51 rows=1 width=19) (actual time=17073.046..17073.053 rows=16 loops=1)" 
"  Group Key: date_part('year'::text, master.insert_date), date_part('month'::text, master.insert_date)" 
"  -> Nested Loop (cost=0.43..43860.32 rows=15317 width=19) (actual time=0.056..15951.178 rows=843647 loops=1)" 
"    -> Seq Scan on master (cost=0.00..18881.38 rows=3127 width=12) (actual time=0.027..636.202 rows=182338 loops=1)" 
"     Filter: ((date(insert_date) >= '2015-01-01'::date) AND (date(insert_date) <= '2016-12-31'::date))" 
"     Rows Removed by Filter: 443031" 
"    -> Index Scan using idx_detail_master_key on detail (cost=0.43..7.89 rows=7 width=15) (actual time=0.055..0.077 rows=5 loops=182338)" 
"     Index Cond: (master_key = master.master_key)" 
"     Filter: (amount IS NOT NULL)" 
"     Rows Removed by Filter: 2" 
"Planning time: 105.317 ms" 
"Execution time: 17073.396 ms" 

Also meine Idee war, die Indexgrößen zu reduzieren, indem Sie sie teilweise definieren. In den meisten Fällen werden nur Daten der letzten 2 Jahre abgefragt.

Also habe ich versucht, so etwas wie das:

CREATE INDEX idx_detail_table_master_keys 
ON detail (master_key) 
WHERE master_key in (SELECT master_key FROM master WHERE (extract(year from insert_date) = 2016) or (extract(year from insert_date) = 2015)) 

Der Grund hierfür ist es nicht die endgültige Version sollte nur ein Proof of Concept und es ist fehlgeschlagen. PGAdmin Sagt mir, dass ich keine Subselects für die Indexerstellung verwenden darf.

Meine Frage ist also: Ist es möglich, einen partiellen Index zu erstellen, basierend auf den Daten einer anderen Tabelle?

Und natürlich wäre ich dankbar für irgendwelche Tipps, die Konstellationen wie diese beschleunigen.

Bezug

+0

[Bearbeiten] Ihre Frage ein und fügen Sie die Ausgabe von ': Eine ausführlichere Beschreibung zu diesen Themen finden Sie hier erklären (analysieren, verbose) 'für Ihre Abfrage. Nicht verwandt, aber: Sie sollten wirklich beginnen, einen expliziten 'JOIN'-Operator anstelle des alten, veralteten impliziten Joins in der' Where'-Klausel zu verwenden. –

+0

@a_horse_with_no_name: Ich musste die Detailtabelle und die Abfrage deaktivieren, um sie an das EXPLAIN-Ergebnis anzupassen. Aber es ist getan;). Die Idee dieser Frage ist nicht nur meine aktuelle Abfrage zu verbessern, sondern zu lernen, wie ich ähnliche Konstrukte im Allgemeinen beschleunigen kann. Deshalb habe ich versucht, es so weit wie möglich zu vereinfachen. – Mike

+1

@Mike Versuchen Sie eher, Index für 'Datum (Einfügedatum)' wie 'CREATE INDEX IDX_detail_table_master_insert ON Master USING btree (Datum (Einfügung_Datum)) zu erstellen –

Antwort

0

es nicht möglich ist, einen Teilindex, gründend auf den Daten einer anderen Tabelle zu erstellen, da relationale Datenbanken wie postgresql drei Möglichkeiten des Verbindens haben: verschachtelte Schleifen, Hash-Join und sort-merge. Alle diese Methoden laden die Tabellen einer Verknüpfung separat. Da der Datenbankoptimierer entscheidet, welche dieser Methoden verwendet wird und in welche Richtung der Join ausgeführt wird, ist es nicht sinnvoll, einen Tabellenindex zu erstellen, der Daten einer anderen Tabelle abdeckt. Aus diesem Grund können Sie solche Indizes nicht definieren. http://use-the-index-luke.com/sql/join (und die folgenden Abschnitte des Online-Buchs)

Zur weiteren Optimierung finden Sie in den Kommentar von Gabriels Gesander

Verwandte Themen