PostgreSQL/PostGIS
PostgreSQL mit PostGIS-Erweiterung ist die zentrale Geodatenbank von p2d2.
Installation
PostgreSQL 15
# Auf Debian/Ubuntu
apt install postgresql-15 postgresql-client-15
# Service starten
systemctl enable postgresql
systemctl start postgresqlPostGIS 3.4
# PostGIS-Paket installieren
apt install postgresql-15-postgis-3
# In Datenbank aktivieren
sudo -u postgres psql -d p2d2 -c "CREATE EXTENSION postgis;"
sudo -u postgres psql -d p2d2 -c "CREATE EXTENSION postgis_topology;"Datenbank einrichten
Datenbank und User erstellen
-- Als postgres-User
CREATE USER p2d2 WITH PASSWORD 'secure_password';
CREATE DATABASE p2d2 OWNER p2d2;
-- In p2d2-Datenbank
\c p2d2
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;Schema erstellen
-- Hauptschema für Features
CREATE SCHEMA features;
GRANT ALL ON SCHEMA features TO p2d2;
-- Schema für Metadaten
CREATE SCHEMA metadata;
GRANT ALL ON SCHEMA metadata TO p2d2;
-- Schema für Versionierung
CREATE SCHEMA history;
GRANT ALL ON SCHEMA history TO p2d2;Tabellen erstellen
Feature-Tabelle
CREATE TABLE features.friedhoefe (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
kategorie VARCHAR(50),
adresse TEXT,
telefon VARCHAR(50),
email VARCHAR(100),
webseite VARCHAR(255),
oeffnungszeiten TEXT,
beschreibung TEXT,
geom GEOMETRY(MultiPolygon, 4326),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(100),
updated_by VARCHAR(100),
status VARCHAR(20) DEFAULT 'draft',
qc_status VARCHAR(20),
qc_by VARCHAR(100),
qc_at TIMESTAMP
);
-- Räumlicher Index
CREATE INDEX idx_friedhoefe_geom ON features.friedhoefe USING GIST(geom);
-- Attribut-Indizes
CREATE INDEX idx_friedhoefe_name ON features.friedhoefe(name);
CREATE INDEX idx_friedhoefe_status ON features.friedhoefe(status);Versionierungs-Tabelle
CREATE TABLE history.friedhoefe_history (
history_id SERIAL PRIMARY KEY,
feature_id INTEGER,
operation VARCHAR(10),
old_data JSONB,
new_data JSONB,
changed_by VARCHAR(100),
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Trigger für Versionierung
-- Trigger-Funktion
CREATE OR REPLACE FUNCTION history.log_changes()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'UPDATE') THEN
INSERT INTO history.friedhoefe_history (feature_id, operation, old_data, new_data, changed_by)
VALUES (OLD.id, 'UPDATE', row_to_json(OLD), row_to_json(NEW), NEW.updated_by);
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
INSERT INTO history.friedhoefe_history (feature_id, operation, old_data, changed_by)
VALUES (OLD.id, 'DELETE', row_to_json(OLD), OLD.updated_by);
RETURN OLD;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO history.friedhoefe_history (feature_id, operation, new_data, changed_by)
VALUES (NEW.id, 'INSERT', row_to_json(NEW), NEW.created_by);
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
-- Trigger erstellen
CREATE TRIGGER friedhoefe_audit
AFTER INSERT OR UPDATE OR DELETE ON features.friedhoefe
FOR EACH ROW EXECUTE FUNCTION history.log_changes();Performance-Tuning
postgresql.conf
# Shared Buffers (25% of RAM)
shared_buffers = 8GB
# Effective Cache (50-75% of RAM)
effective_cache_size = 24GB
# Work Memory
work_mem = 256MB
# Maintenance Work Memory
maintenance_work_mem = 2GB
# Max Parallel Workers
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
# Random Page Cost (SSD)
random_page_cost = 1.1
# Logging
log_min_duration_statement = 1000
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h 'Connection-Pooling mit PgBouncer
# PgBouncer installieren
apt install pgbouncer
# /etc/pgbouncer/pgbouncer.ini
[databases]
p2d2 = host=localhost port=5432 dbname=p2d2
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 100Backup-Strategie
Logical Backup (pg_dump)
# Vollständiger Dump
pg_dump -U p2d2 -F c -b -v -f p2d2_$(date +%Y%m%d).backup p2d2
# Nur Schema
pg_dump -U p2d2 -s -f p2d2_schema.sql p2d2
# Nur Daten einer Tabelle
pg_dump -U p2d2 -t features.friedhoefe -f friedhoefe_data.sql p2d2Physical Backup (pg_basebackup)
# Base-Backup für PITR
pg_basebackup -U replication -D /backup/pg_base -Fp -Xs -P
# WAL-Archivierung aktivieren
# postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /backup/wal/%f && cp %p /backup/wal/%f'Automatisches Backup
# /usr/local/bin/backup-p2d2.sh
#!/bin/bash
BACKUP_DIR="/backup/postgresql"
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -U p2d2 -F c -f $BACKUP_DIR/p2d2_$DATE.backup p2d2
# Alte Backups löschen (älter als 30 Tage)
find $BACKUP_DIR -name "p2d2_*.backup" -mtime +30 -delete
# Cronjob: täglich um 2 Uhr
# 0 2 * * * /usr/local/bin/backup-p2d2.shMonitoring
pg_stat_statements
-- Extension aktivieren
CREATE EXTENSION pg_stat_statements;
-- Langsamste Queries
SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;Prometheus-Exporter
# postgres_exporter installieren
docker run -d \
--name postgres-exporter \
-p 9187:9187 \
-e DATA_SOURCE_NAME="postgresql://p2d2:password@localhost:5432/p2d2?sslmode=disable" \
prometheuscommunity/postgres-exporterWartung
VACUUM und ANALYZE
# Automatisches VACUUM
# postgresql.conf:
autovacuum = on
autovacuum_naptime = 1min
# Manuelles VACUUM
VACUUM ANALYZE features.friedhoefe;
# VACUUM FULL (sperrt Tabelle!)
VACUUM FULL features.friedhoefe;Reindex
-- Index neubauen
REINDEX INDEX idx_friedhoefe_geom;
-- Alle Indizes einer Tabelle
REINDEX TABLE features.friedhoefe;VACUUM FULL
VACUUM FULL sperrt die Tabelle exklusiv und kann lange dauern! Nur in Wartungsfenstern durchführen.