CodeGym /Kurse /SQL SELF /Analyse typischer Fehler beim Erstellen von analytischen ...

Analyse typischer Fehler beim Erstellen von analytischen Prozeduren

SQL SELF
Level 60 , Lektion 4
Verfügbar

Heute, um diese epische Reise durch PL/pgSQL abzuschließen, lass uns klarstellen: Fehler in analytischen Prozeduren sind unvermeidlich. Warum? Weil man in der Analytics-Welt mit großen Datenmengen, komplexen Berechnungen und manchmal ziemlich fiesen Bedingungen arbeitet. Je komplizierter die Abfrage oder Prozedur, desto mehr ähnelt sie einem Labyrinth, in dem ein paar falsche Schritte zu falschen Ergebnissen führen können.

Zum Glück sind die meisten Fehler typisch und lassen sich vorhersagen (und verhindern). Lass uns sie nacheinander anschauen.

1. Fehlende Indizes auf Schlüsselfeldern

Indizes sind wie ein Navi in der Datenbankwelt. Wenn sie fehlen, muss die Datenbank zu Fuß durch alle Zeilen der Tabelle laufen. Bei kleinen Tabellen geht das noch, aber sobald die Daten auf Millionen Zeilen anwachsen, werden deine Abfragen langsamer als Windows XP auf einem Pentium III.

Angenommen, du hast eine Bestellungen-Tabelle und willst die Verkäufe des letzten Monats berechnen:

SELECT SUM(order_total)
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '1 month';

Wenn das Feld order_date keinen Index hat, macht PostgreSQL einen kompletten Table Scan (Seq Scan). Und das ist fast immer langsam.

Lösung: Benutz Indizes! Das geht ganz einfach mit:

CREATE INDEX idx_order_date ON orders (order_date);

Jetzt kann PostgreSQL viel schneller nach order_date suchen.

Verwendung ineffizienter Abfragen

Manche Abfragen sehen schick aus, funktionieren aber wie ein Betonklotz als Schlüssel. Zum Beispiel Subqueries, die man durch Joins (JOIN) ersetzen könnte, oder unnötige Filter.

Stattdessen:

SELECT product_id, SUM(order_total)
FROM orders
WHERE product_id IN (SELECT id FROM products WHERE category = 'electronics')
GROUP BY product_id;

Besser so:

SELECT o.product_id, SUM(o.order_total)
FROM orders o
JOIN products p ON o.product_id = p.id
WHERE p.category = 'electronics'
GROUP BY o.product_id;

So muss PostgreSQL nicht für jede Zeile eine Subquery ausführen und alles läuft viel schneller.

Falsche Struktur temporärer Tabellen

Temporäre Tabellen können ein mächtiges Tool sein, wenn du sie clever nutzt. Aber wenn du vergisst, die nötigen Spalten oder Indizes hinzuzufügen, wird die temporäre Tabelle zum Flaschenhals und bremst alles aus.

Hier ein Beispiel. Wir erstellen eine temporäre Tabelle für Zwischenberechnungen:

CREATE TEMP TABLE temp_sales AS
SELECT region, SUM(order_total) AS total_sales
FROM orders
GROUP BY region;

Aber dann willst du nach total_sales filtern, und es gibt keinen Index auf diesem Feld.

Bevor du eine temporäre Tabelle nutzt, überleg dir, wie du damit arbeitest. Wenn du nach einer Spalte filtern willst, füge einen Index hinzu:

CREATE INDEX idx_temp_sales_total_sales ON temp_sales (total_sales);

Rechenfehler (zum Beispiel Division durch Null)

Division durch Null ist ein Klassiker in der Analytics. SQL wird diesen Fehler nicht einfach ignorieren, sondern die Abfrage sofort abbrechen.

Angenommen, du willst den durchschnittlichen Bestellwert berechnen:

SELECT SUM(order_total) / COUNT(*) AS avg_order_value
FROM orders;

Wenn es in der Tabelle orders keine Daten gibt, passiert eine Division durch Null und die Abfrage endet mit einem Fehler.

Um das zu vermeiden, fang den Fall ab, wenn der Zähler null ist:

SELECT
    CASE 
        WHEN COUNT(*) = 0 THEN 0
        ELSE SUM(order_total) / COUNT(*)
    END AS avg_order_value
FROM orders;

Fehlendes Logging und fehlende Kontrolle der Ausführung

PL/pgSQL-Prozeduren können komplex sein und aus mehreren Schritten bestehen: von Zwischenberechnungen bis zu finalen Reports. Wenn in dieser Kette etwas schiefgeht, weißt du ohne Logging einfach nicht, an welcher Stelle und warum alles schiefgelaufen ist.

Angenommen, wir bauen eine Prozedur zur Berechnung von Metriken, vergessen aber, die erwarteten Daten in jedem Schritt zu prüfen. Am Ende stürzt die ganze Prozedur ab, wenn sie auf unerwartete Daten trifft (zum Beispiel leere Tabellen).

Um das zu vermeiden, kannst du Logging an jedem wichtigen Schritt der Prozedur einbauen. Zum Beispiel:

RAISE NOTICE 'Start der Verkaufsberechnung';
-- Dein Code hier...

RAISE NOTICE 'Modul % erfolgreich abgeschlossen', modul;

Für komplexere Prozeduren ist es besser, Logs in einer speziellen Tabelle zu speichern:

CREATE TABLE log_analytics (
    log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    log_message TEXT
);

In der Prozedur fügst du dann ein:

INSERT INTO log_analytics (log_message)
VALUES ('Prozedur erfolgreich abgeschlossen');

Performance-Probleme durch fehlende Optimierung

Optimierung ist nicht nur für Abfragen wichtig, sondern auch für Prozeduren selbst. Wenn viele User die Prozedur nutzen, kann sie schnell zum Flaschenhals im System werden.

Hier zum Beispiel eine Prozedur, die Metriken für alle Regionen neu berechnet, auch wenn du nur Daten für eine Region brauchst:

CREATE OR REPLACE FUNCTION calculate_sales()
RETURNS VOID AS $$
BEGIN
    -- Neuberechnung für alle Regionen
    INSERT INTO sales_metrics(region, total_sales)
    SELECT region, SUM(order_total)
    FROM orders
    GROUP BY region;
END;
$$ LANGUAGE plpgsql;

Das erzeugt unnötige Last.

Wie geht's besser? Füge einen Parameter für die Region hinzu, um gezielt zu filtern:

CREATE OR REPLACE FUNCTION calculate_sales(p_region TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO sales_metrics(region, total_sales)
    SELECT region, SUM(order_total)
    FROM orders
    WHERE region = p_region
    GROUP BY region;
END;
$$ LANGUAGE plpgsql;

Jetzt verarbeitet die Prozedur nur die nötigen Daten und die Abfrage ist schneller fertig.

Ignorieren von Performance-Analyse-Tools

Tools wie EXPLAIN ANALYZE sind deine besten Freunde, wenn du wissen willst, wo deine Abfragen langsam sind und wie du das fixen kannst. Wenn du eine Prozedur schreibst, aber ihre Performance nicht analysierst, bist du wie ein Quantencomputer-Programmierer ohne Oszilloskop – es läuft irgendwie, aber was wirklich passiert, weiß keiner.

Hier ein Beispiel. Das Problem in dieser Abfrage siehst du mit EXPLAIN ANALYZE sofort:

SELECT *
FROM orders
WHERE EXTRACT(YEAR FROM order_date) = 2023;

Diese Abfrage ist ineffizient, weil die Funktion EXTRACT() die Indizes ausschaltet.

Das Problem löst du so. Analysiere die Abfrage mit:

EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE order_date >= DATE '2023-01-01' AND order_date < DATE '2024-01-01';

Wie kann man typische Fehler vermeiden?

Um Fehler zu vermeiden, halte dich an diese Praktiken:

  1. Setze Indizes auf Felder, die du zum Filtern oder Joinen nutzt.
  2. Optimiere deine Abfragen: Vermeide unnötige Subqueries, nutze JOIN.
  3. Logge die Ausführung. Das macht das Debugging viel einfacher, falls mal was schiefgeht.
  4. Check deine Prozeduren immer mit Tools wie EXPLAIN ANALYZE.
  5. Hast du Performance-Probleme? Überleg dir Partitionierung oder überarbeite die Logik deiner Abfrage.

Jetzt bist du gewappnet, um Fehler vorherzusehen und zu verhindern, die deine Analysten sonst ohne Kaffeemaschine und WLAN dastehen lassen würden – nur wegen langsamer Abfragen.

1
Umfrage/Quiz
Automatische Berichtserstellung, Level 60, Lektion 4
Nicht verfügbar
Automatische Berichtserstellung
Automatische Berichtserstellung
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION