218 Zeilen
10 KiB
Markdown
218 Zeilen
10 KiB
Markdown
|
|
# Flashcard Deck: PostgreSQL Grundlagen & Konfiguration
|
||
|
|
|
||
|
|
**Thema**: PostgreSQL-spezifisches Wissen fuer Solution2-Entwickler
|
||
|
|
**Schwierigkeit**: Anfaenger -> Fortgeschritten
|
||
|
|
**Karten**: 20
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 1 | Basis
|
||
|
|
**Q:** Welcher DAM (Data Access Module) wird fuer PostgreSQL in Omnis verwendet?
|
||
|
|
**A:** `PGSQLDAM` (auch als `PostgresDAM` in der INI-Datei). Omnis laedt die Bibliothek `dampgsql.so` (Linux) bzw. `dampgsql.dll` (Windows), die wiederum `libpq` (die offizielle PostgreSQL-Client-Bibliothek) nutzt.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 2 | Basis
|
||
|
|
**Q:** Was ist `libpq` und warum ist es fuer Solution2 wichtig?
|
||
|
|
**A:** `libpq` ist die offizielle C-Client-Bibliothek von PostgreSQL. Omnis' `dampgsql.so` nutzt `dlopen()` um libpq zur Laufzeit zu laden. Ohne libpq crasht Omnis beim Datenbankzugriff mit "double free or corruption" (SIGABRT) oder "general protection fault" (SIGSEGV). In Docker muss ein Symlink erstellt werden: `ln -s /usr/lib/x86_64-linux-gnu/libpq.so.5 /opt/omnis/libpq.so`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 3 | Basis
|
||
|
|
**Q:** Wie sieht die PostgreSQL-Verbindungskonfiguration in der Solution2-INI-Datei aus?
|
||
|
|
**A:** ```
|
||
|
|
[SQL]
|
||
|
|
Database=PostgreSQL
|
||
|
|
DatabaseName=masterdemo
|
||
|
|
HostIP=postgres
|
||
|
|
HostPort=5432
|
||
|
|
UserName=soluser
|
||
|
|
DAM=PostgresDAM
|
||
|
|
Schema=soluser
|
||
|
|
```
|
||
|
|
**ACHTUNG:** Es muss `HostPort` heissen, NICHT `Port`! Omnis liest `$getSectionParameter('SQL','HostPort')`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 4 | Basis
|
||
|
|
**Q:** Welche Standard-Rollen gibt es in einer Solution2 PostgreSQL-Datenbank?
|
||
|
|
**A:** - `sol2_system`: Schema-Owner, erstellt Tabellen und Objekte
|
||
|
|
- `soluser`: Anwendungsbenutzer mit CRUD-Rechten, wird von Omnis verwendet
|
||
|
|
- Optional: `kunde_readonly`: Lesezugriff fuer Reporting/Monitoring.
|
||
|
|
Rechte werden ueber `ALTER DEFAULT PRIVILEGES` automatisch vergeben: `ALTER DEFAULT PRIVILEGES FOR ROLE sol2_system GRANT ALL ON TABLES TO soluser;`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 5 | Basis
|
||
|
|
**Q:** Was ist der Unterschied zwischen `$logon()` und `$execdirect()` in Omnis?
|
||
|
|
**A:** - `$logon()` erstellt eine **persistente Datenbank-Session** mit voller Transaktionskontrolle ($begin/$commit/$rollback)
|
||
|
|
- `$execdirect()` fuehrt ein **einzelnes SQL-Statement** direkt aus, mit Auto-Commit.
|
||
|
|
Fuer alles was zusammenhaengt (z.B. Auftrag + Positionen anlegen) MUSS eine Session mit expliziter Transaktion verwendet werden.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 6 | Basis
|
||
|
|
**Q:** Wie funktioniert eine Transaktion in Omnis/Solution2?
|
||
|
|
**A:** ```omnis
|
||
|
|
Do lSess.$begin() Returns #F ;; START TRANSACTION
|
||
|
|
Do lStmt.$execdirect(lSQL1) Returns #F
|
||
|
|
Do lStmt.$execdirect(lSQL2) Returns #F
|
||
|
|
If lAllesOK
|
||
|
|
Do lSess.$commit() Returns #F ;; COMMIT
|
||
|
|
Else
|
||
|
|
Do lSess.$rollback() Returns #F ;; ROLLBACK
|
||
|
|
End If
|
||
|
|
```
|
||
|
|
Immer `#F` (flag) pruefen! Bei Fehler sofort `$rollback()`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 7 | Mittel
|
||
|
|
**Q:** Was sind die wichtigsten PostgreSQL-Tuning-Parameter fuer Solution2?
|
||
|
|
**A:** - `shared_buffers` = 25% RAM (Cache fuer Tabellendaten)
|
||
|
|
- `effective_cache_size` = 75% RAM (Planer-Hint fuer OS-Cache)
|
||
|
|
- `work_mem` = RAM / (max_connections * 4) (pro Query-Sortierung)
|
||
|
|
- `maintenance_work_mem` = RAM / 32 (fuer VACUUM, CREATE INDEX)
|
||
|
|
- `max_connections` = 100 (Standard, reicht fuer Omnis + n8n + pgAdmin)
|
||
|
|
- `log_min_duration_statement` = 250ms (Slow-Query-Logging)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 8 | Mittel
|
||
|
|
**Q:** Was passiert wenn in PostgreSQL ein `SELECT` ohne Transaktion laeuft?
|
||
|
|
**A:** PostgreSQL wrapt jedes einzelne Statement automatisch in eine Transaktion (Auto-Commit). Das bedeutet: Ein einzelnes `SELECT` sieht immer einen konsistenten Snapshot. Aber wenn du ZWEI aufeinanderfolgende SELECTs ohne explizite Transaktion machst, koennen sie unterschiedliche Daten sehen, weil dazwischen ein anderer Benutzer etwas geaendert haben kann.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 9 | Mittel
|
||
|
|
**Q:** Was sind die PostgreSQL Isolation Levels und welcher wird in Solution2 typisch verwendet?
|
||
|
|
**A:** - `READ COMMITTED` (Standard in PostgreSQL und Solution2): Jedes Statement sieht nur Daten die VOR dem Statement committed wurden
|
||
|
|
- `REPEATABLE READ`: Die gesamte Transaktion sieht den Snapshot vom Transaktionsbeginn
|
||
|
|
- `SERIALIZABLE`: Strengste Isolation, verhindert Phantom Reads.
|
||
|
|
Solution2 nutzt den Standard `READ COMMITTED`. Das reicht fuer die meisten ERP-Operationen.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 10 | Mittel
|
||
|
|
**Q:** Was ist der Unterschied zwischen einer PostgreSQL `SEQUENCE` und einem Auto-Increment?
|
||
|
|
**A:** In PostgreSQL gibt es kein echtes "Auto-Increment". Stattdessen:
|
||
|
|
- `SERIAL` / `BIGSERIAL`: Erstellt automatisch eine Sequence und setzt `DEFAULT nextval('seq_name')`
|
||
|
|
- `GENERATED ALWAYS AS IDENTITY`: Moderner Standard (PostgreSQL 10+), verhindert manuelle Werte
|
||
|
|
- `SEQUENCE`: Eigenstaendiges Datenbankobjekt, kann von mehreren Tabellen geteilt werden.
|
||
|
|
Solution2 nutzt haeufig eigene Counter-Tabellen statt Sequences, um Nummernkreise flexibler zu steuern.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 11 | Mittel
|
||
|
|
**Q:** Wie funktioniert Soft-Delete in Solution2 und warum wird es verwendet?
|
||
|
|
**A:** Jede Solution2-Tabelle hat eine Spalte `valid` (BOOLEAN). Statt `DELETE FROM parts WHERE id = 42` wird `UPDATE parts SET valid = false WHERE id = 42` verwendet. Gruende:
|
||
|
|
- Referenzielle Integritaet bleibt erhalten (Foreign Keys zeigen noch auf den Datensatz)
|
||
|
|
- Historische Daten bleiben fuer Reports verfuegbar
|
||
|
|
- Versehentliches Loeschen ist reversibel.
|
||
|
|
**WICHTIG:** Bei SELECTs immer `WHERE valid = true` filtern!
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 12 | Mittel
|
||
|
|
**Q:** Welche Audit-Spalten hat jede Solution2-Tabelle?
|
||
|
|
**A:** - `created` (TIMESTAMP): Wann wurde der Datensatz erstellt
|
||
|
|
- `modtime` (TIMESTAMP): Letzte Aenderung
|
||
|
|
- `revisor` (INTEGER): ID des Benutzers der zuletzt geaendert hat
|
||
|
|
- `valid` (BOOLEAN): Soft-Delete Flag (true = aktiv, false = geloescht)
|
||
|
|
Diese Spalten werden automatisch von den T_Super-Methoden befuellt. Nie manuell setzen!
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 13 | Fortgeschritten
|
||
|
|
**Q:** Warum darf man Stammdaten (Artikel, Mitarbeiter, Adressen) NICHT per SQL-INSERT anlegen?
|
||
|
|
**A:** Solution2 erstellt beim Anlegen automatisch abhaengige Datensaetze:
|
||
|
|
- **Artikel**: Versionseintraege, Lifecycle, Lagerzuordnungen, Zusatzfeld-Defaults, Audit-Trail, Stuecklistenstrukturen
|
||
|
|
- **Mitarbeiter**: Gruppenzuordnungen, Berechtigungen, Passwort-Records, Personaldaten
|
||
|
|
- **Adressen**: Zahlungsbedingungen, Kommunikationseintraege, Rollenzuordnungen.
|
||
|
|
Ein SQL-INSERT erzeugt nur den Hauptdatensatz — die abhaengigen Daten fehlen, was zu Fehlern und inkonsistenten Zustaenden fuehrt. Richtig: Ueber Solution2-UI oder rtDataImport-Service.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 14 | Fortgeschritten
|
||
|
|
**Q:** Was ist `T_Super` in Solution2?
|
||
|
|
**A:** `T_Super` ist die **Basis-Tabellenklasse** von der alle Tabellen-Klassen erben. Sie stellt gemeinsame Methoden bereit:
|
||
|
|
- `$select()`: Daten laden mit automatischer Schema/WHERE-Behandlung
|
||
|
|
- `$insert()`: Neuen Datensatz anlegen (setzt created, modtime, revisor automatisch)
|
||
|
|
- `$update()`: Datensatz aendern (aktualisiert modtime und revisor)
|
||
|
|
- `$delete()`: Soft-Delete (setzt valid = false).
|
||
|
|
Es gibt auch `T_SuperVersion` fuer versionierte Tabellen (z.B. Artikelstaemme mit Aenderungshistorie).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 15 | Fortgeschritten
|
||
|
|
**Q:** Was darf man per SQL aendern und was nicht?
|
||
|
|
**A:** **Erlaubt (UPDATE):**
|
||
|
|
- Enterprise-Daten (Firmenstamm), SystemKey, DBStatus
|
||
|
|
- Nummernkreise zuruecksetzen (UPDATE nextnumber)
|
||
|
|
- Konfigurationstabellen (Warengruppen, Zusatzfelder)
|
||
|
|
- Passwort-Reset
|
||
|
|
**Erlaubt (DELETE/TRUNCATE):**
|
||
|
|
- Bewegungsdaten (Auftraege, Rechnungen) wenn sicher
|
||
|
|
**VERBOTEN (INSERT):**
|
||
|
|
- Artikel, Mitarbeiter, Adressen, Dokumente — immer ueber Solution2 UI oder Services!
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 16 | Fortgeschritten
|
||
|
|
**Q:** Wie behandelt Solution2 BLOBs (Binary Large Objects) in PostgreSQL?
|
||
|
|
**A:** BLOBs werden in der Tabelle `documentcontent` gespeichert (z.B. angehaengte PDFs, Bilder). Bei der Migration von FrontBase nach PostgreSQL gibt es zwei Strategien:
|
||
|
|
- **Phase-1 (Inline)**: BLOBs direkt mit den Daten importieren — einfach, aber langsam bei grossen DBs (> 2GB)
|
||
|
|
- **Phase-2 (Separat)**: Erst Struktur + Daten, dann BLOBs nachtraeglich importieren — empfohlen fuer Produktion.
|
||
|
|
PostgreSQL speichert grosse BLOBs via TOAST (The Oversized Attribute Storage Technique) automatisch komprimiert.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 17 | Fortgeschritten
|
||
|
|
**Q:** Was ist TOAST in PostgreSQL?
|
||
|
|
**A:** TOAST (The Oversized Attribute Storage Technique) ist PostgreSQLs Mechanismus fuer grosse Feldwerte. Wenn ein Wert groesser als ca. 2kB ist, wird er automatisch:
|
||
|
|
1. Erst komprimiert (LZ-Kompression)
|
||
|
|
2. Wenn immer noch zu gross: In eine separate TOAST-Tabelle ausgelagert.
|
||
|
|
Das passiert transparent — fuer die Anwendung sieht es aus wie ein normales Feld. Relevant fuer Solution2s `documentcontent`-Tabelle mit grossen Anhaengen.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 18 | Fortgeschritten
|
||
|
|
**Q:** Wie funktioniert die Fehlerbehandlung bei SQL-Operationen in Omnis?
|
||
|
|
**A:** ```omnis
|
||
|
|
Do lStmt.$execute(lParam) Returns #F
|
||
|
|
If not(flag true)
|
||
|
|
Calculate lCode as lSess.$lasterror
|
||
|
|
Calculate lText as lSess.$lasterrortext
|
||
|
|
OK message {SQL-Fehler [lCode]: [lText]}
|
||
|
|
Do lSess.$rollback() Returns #F
|
||
|
|
End If
|
||
|
|
```
|
||
|
|
**Wichtig:** `#F` (flag) wird nach JEDER SQL-Operation gesetzt. `$lasterror` liefert den PostgreSQL-Fehlercode, `$lasterrortext` die lesbare Meldung. Bei Deadlocks (error code 40P01) kann ein Retry sinnvoll sein.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 19 | Fortgeschritten
|
||
|
|
**Q:** Was muss man bei Docker-Deployments fuer die PostgreSQL-Verbindung beachten?
|
||
|
|
**A:** - `HostIP` in der INI muss der **Docker-Container-Name** sein (z.B. `postgres`), NICHT `localhost` oder `127.0.0.1`
|
||
|
|
- Alle Container muessen im gleichen Docker-Network sein (z.B. `senex-net`)
|
||
|
|
- `libpq.so` muss als Symlink im Omnis-Home-Verzeichnis existieren
|
||
|
|
- `pg_hba.conf` muss Verbindungen vom Docker-Netzwerk erlauben: `host all all 172.16.0.0/12 scram-sha-256`
|
||
|
|
- Session-Timeouts beachten: PostgreSQL schliesst idle Connections nach `idle_in_transaction_session_timeout`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Karte 20 | Fortgeschritten
|
||
|
|
**Q:** Wie prueft man in PostgreSQL langsame Queries und was bedeutet das fuer Solution2?
|
||
|
|
**A:** ```sql
|
||
|
|
-- Slow Query Log aktivieren (postgresql.conf)
|
||
|
|
log_min_duration_statement = 250 -- Alles > 250ms loggen
|
||
|
|
|
||
|
|
-- Ausfuehrungsplan anzeigen
|
||
|
|
EXPLAIN ANALYZE SELECT * FROM orders WHERE valid = true AND status = 'A';
|
||
|
|
|
||
|
|
-- Laufende Queries anzeigen
|
||
|
|
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
|
||
|
|
FROM pg_stat_activity WHERE state = 'active';
|
||
|
|
```
|
||
|
|
**Typische Solution2-Bottlenecks:** Fehlende Indizes auf `valid`-Spalte, grosse JOINs ueber orders/orderitems ohne Einschraenkung, LIKE-Suchen ohne Index.
|