2012-04-13 18 views
1

Ich arbeite an einem großen PostgreSQL-Projekt, das leider in der Produktion (3 Millionen Datensätze in einer Tabelle mit 90 Spalten) eine Abfrage (ein select/join mit 2 Bedingungen) in etwa 2 Minuten ausführt.PostgreSQL-Optimierung

Angenommen, es gibt nichts zu optimieren auf meine Abfrage, gibt es irgendwelche Einstellungen, die ich ändern könnte, um es schneller laufen zu lassen? Diese ist die Konfiguration der Datenbank, und ich habe keine Ahnung, was meinen Bedürfnissen entspricht:

version PostgreSQL 8.4.4 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44), 32-bit 
checkpoint_completion_target 0.9 
checkpoint_segments 10 
custom_variable_classes pg_stat_statements 
effective_cache_size 1GB 
lc_collate fr_FR.UTF-8 
lc_ctype fr_FR.UTF-8 
listen_addresses * 
log_autovacuum_min_duration 0 
log_line_prefix %t [%p]: [%l-1] user=%u,db=%d 
log_min_duration_statement 30s 
logging_collector on 
maintenance_work_mem 128MB 
max_connections 100 
max_stack_depth 2MB 
pg_stat_statements.max 1000 
pg_stat_statements.save on 
pg_stat_statements.track all 
random_page_cost 1.5 
server_encoding UTF8 
shared_buffers 128MB 
TimeZone Europe/Paris 
track_functions pl 
wal_buffers 1MB 
work_mem 8MB 

Abfrage:

SELECT distinct 
    ((Table_Commande_Historique.COD_STECIAL 
    || ',' || Table_Commande_Historique.COD_MCIAL 
    || ',' || Table_Commande_Historique.NUM_REC_CLI 
    || ',' || Table_Commande_Historique.NUM_DNT_CLI 
    || ',' || Table_Commande_Historique.NUM_DDE)) cle 
FROM G1DDE2_DDE Table_Commande_Historique 
inner join "K2VER2_VER" ver 
    on (Table_Commande_Historique.NUM_REC_CLI 
     = (string_to_array(ver.num_cle,','))[3]::int 
    OR Table_Commande_Historique.NUM_DNT_CLI 
     = (string_to_array(ver.num_cle,','))[3]::int 
    OR ver.num_cle = (Table_Commande_Historique.COD_MCIAL 
        || ',' || Table_Commande_Historique.NUM_REC_CLI) 
    OR ver.num_cle = (Table_Commande_Historique.COD_MCIAL 
        || ',' || Table_Commande_Historique.NUM_DNT_CLI)); 

Indizes:

CREATE INDEX idx_combo1 
    ON g1dde2_dde 
    USING btree 
    (((cod_mcial || ','::text) || num_rec_cli)); 

    CREATE INDEX idx_combo2 
    ON g1dde2_dde 
    USING btree 
    (((cod_mcial || ','::text) || num_dnt_cli)); 

    CREATE INDEX idx_dnt 
    ON g1dde2_dde 
    USING btree 
    (num_dnt_cli); 

    CREATE INDEX idx_rec 
    ON g1dde2_dde 
    USING btree 
    (num_rec_cli); 

    CREATE INDEX idx_k2ver3sb 
    ON "K2VER2_VER" 
    USING btree 
    (num_cle); 

ERKLÄREN:

"HashAggregate (cost=197.97..201.77 rows=69 width=29)" 
" -> Nested Loop (cost=1.29..197.35 rows=248 width=29)" 
"  -> Seq Scan on "K2VER2_VER" ver (cost=0.00..2.58 rows=58 width=19)" 
"  -> Bitmap Heap Scan on g1dde2_dde table_commande_historique (cost=1.29..2.84 rows=5 width=29)" 
"    Recheck Cond: ((table_commande_historique.num_rec_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer) OR (table_commande_historique.num_dnt_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer) OR ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_rec_cli)::text)) OR ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_dnt_cli)::text)))" 
"    -> BitmapOr (cost=1.29..1.29 rows=5 width=0)" 
"     -> Bitmap Index Scan on idx_rec (cost=0.00..0.32 rows=2 width=0)" 
"       Index Cond: (table_commande_historique.num_rec_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer)" 
"     -> Bitmap Index Scan on idx_dnt (cost=0.00..0.32 rows=1 width=0)" 
"       Index Cond: (table_commande_historique.num_dnt_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer)" 
"     -> Bitmap Index Scan on idx_combo1 (cost=0.00..0.32 rows=1 width=0)" 
"       Index Cond: ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_rec_cli)::text))" 
"     -> Bitmap Index Scan on idx_combo2 (cost=0.00..0.32 rows=1 width=0)" 
"       Index Cond: ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_dnt_cli)::text))" 
+1

Zeigen Sie uns Ihre Abfrage, die Tabelle und die Indizes darauf. –

+1

Zeigen Sie die Erklärung ... oder sollen wir raten? –

+0

OK, also sieht es nicht schlecht aus. Die Anzahl der Zeilen ist ziemlich klein. Ist die Erklärung von der Datenbank, wo die Abfrage zu viel Zeit braucht? –

Antwort

3
version PostgreSQL 8.4.4 

Das ist ein Problem. Bitte lesen Sie diese und ein Minor Release betrachten Fixes für Sicherheitslücken und Bugs zu erhalten:

http://www.postgresql.org/support/versioning/

Diese manchmal Fehler enthalten, die Performance-Probleme einführen. Zu überprüfen, was behebt Sie erhalten würden, könnten Sie die 8.4.5 bis 8.4.11 Noten schauen Sie in hier:

http://www.postgresql.org/docs/8.4/static/release.html

Einige der RAM-basierten Einstellungen sind wahrscheinlich zu niedrig, aber ohne zu wissen, wie viel RAM ist auf dem System und was sonst noch dort läuft, gibt es keine Möglichkeit, bestimmte Zahlen vorzuschlagen.

shared_buffers 128MB 

Die übliche Beratung für einen dedizierten Datenbankserver auf Linux ist dies auf 25% des gesamten RAM auf dem System zu setzen, mit einem Maximum von vielleicht 8 GB und passen von dort auf Benchmarking basiert.

effective_cache_size 1GB 

zuteilen Das macht keinen RAM, sondern ermöglicht es dem Planer wiederholt aus einer Datei auf einer Schätzung basiert liest kosten, wie wahrscheinlich ist es nach wie vor von einer früheren Lese in derselben Abfrage im Cache zu sein. Ich schlage vor, dass Sie die Größe von shared_buffers zu dem hinzufügen, was das Betriebssystem als zwischengespeichert anzeigt.

work_mem 8MB 

Dieser ist knifflig. Es kann wirklich helfen, die Leistung auf verschiedene Arten abzufragen, aber hohe Werte neigen dazu, Dinge aus dem Cache zu entfernen, was den Festplattenzugriff erhöht. Sie müssen auch berücksichtigen, dass jede Abfrage diesen Speicherplatz mehrfach (für verschiedene Abfrageschritte) zuweisen kann. Daher sollten Sie normalerweise eine Zuweisung dieser Größe pro Verbindung zulassen. Dies ist ein aus den Gründen ist es oft vorteilhaft, einen Verbindungspool zu verwenden, um eine große Anzahl von Benutzern auf eine begrenzte Anzahl von tatsächlichen Datenbankverbindungen zu trichterieren. Wenn Sie sich eine größere Größe leisten können, ist es sehr hilfreich, diese Abfrage zu unterstützen, da die Bitmap-Index-Scans dadurch möglicherweise nicht "verlustbehaftet" werden und die Indexbedingungen erneut überprüft werden müssen.

Sie setzen cpu_tuple_cost nicht, aber ich finde, dass die Standardeinstellung in der Regel zu niedrig ist, um die besten Pläne insgesamt zu geben. Angesichts der Tatsache, dass Ihr großer Tisch 90 Spalten hat, würde ich vorschlagen, dies von 0,01 auf 0,05 zu erhöhen.

Sie setzen nicht effective_io_concurrency, aber das könnte helfen. Ich würde mit verschiedenen Werten testen. (Natürlich, wenn die Tests laufen die Leistung von Alternativen zu vergleichen, seien Sie vorsichtig über Probleme Caching.)

maintenance_work_mem 128MB 

Je nachdem, wie viel RAM Sie haben, kann dies oder nicht angemessen sein. Es wirkt sich nicht auf Ihr unmittelbares Problem aus, aber die Erhöhung kann dazu beitragen, dass AutoVacuum effizienter ausgeführt wird, und hilft Indexerstellungen schneller auszuführen.

Diese sind wahrscheinlich ein wenig niedrig:

checkpoint_segments 10 
wal_buffers 1MB 

Sie sind nicht Teil Ihrer unmittelbaren Problem, aber sie könnten dazu führen, zusätzliche Datenträger manchmal schreibt, so wäre es wahrscheinlich zu bezahlen, um sie anzupassen. wal_buffers sollte normalerweise 32 MB betragen, es sei denn, Ihr Computer verfügt über einen sehr begrenzten Arbeitsspeicher. checkpoint_segments ist schwer zu schätzen, ohne mehr zu wissen, aber wenn Sie die Logs und Statistiken überprüfen und feststellen, dass Checkpoints zu häufig auftreten, möchten Sie dies möglicherweise erhöhen, bis Checkpoints basierend auf checkpoint_timeout stattfinden.

+0

Bearbeitet, um die Erwähnung von 'effective_io_concurrency' hinzuzufügen und Tippfehler bei' shared_buffers' zu korrigieren. – kgrittn

+0

Das war was ich brauchte! Ich werde am Donnerstag mit den Ergebnissen zurückkommen. Ich bin jetzt im Urlaub. Danke vielmals – Samson