Quiz: Tiefes PostgreSQL – Teil 2
Bist du ein SQL‑Hartnäckiger oder ein SQL‑Weichling?
Teil 2 von 2. Zurück zu Teil 1
Willkommen zu Teil 2 meines Deep Postres Quiz!
Dieses Quiz deckt eine Mischung aus bekannten und weniger bekannten PostgreSQL‑Features und Stolperfallen ab: JOIN, NULL, ANSI SQL, Transaktionen, Interna, Indexierung, Data Sampling … und mehr!
Viel Glück! 🍀
Welche ist ❌ kein gültiger PostgreSQL‑JOIN‑Ausdruck?
Du kanntest CROSS JOIN, oder?
Hat dich JOIN ALL an eine andere Operation denken lassen, UNION ALL?
Die Antwort hier ist JOIN ALL ❌.
Die korrekten JOIN‑Typen sind:
INNER JOIN(Standard‑JOIN)LEFT JOIN(oderLEFT OUTER JOIN)RIGHT JOIN(oderRIGHT OUTER JOIN)FULL JOIN(oderFULL OUTER JOIN)CROSS JOIN(das kartesische Produkt, sofern ein späteresWHERE‑Klausel es filtert)
Wie lautet die (SQL Standard)-Syntax für eine automatisch inkrementierende IDENTITY‑Spalte in PostgreSQL (v10+)?
Während SERIAL noch häufig verwendet wird, ist die SQL Standard‑Methode:
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEYid INT IDENTITY(1,1)ist SQL Server Syntax.id INT AUTO_INCREMENTist MySQL Syntax.id INTEGER AUTO_INCREMENT PRIMARY KEYist MySQL Syntax.
Das hat mehrere Vorteile gegenüber SERIAL:
- Es ist SQL‑Standard‑konform
- Bessere Handhabung des Sequenz‑Eigentums
- Klarere Semantik bei manuellen Einfügungen
- Funktioniert besser mit Replikation
SERIAL ist eigentlich nur eine Kurzschreibweise zum Erzeugen einer Sequenz und zum Setzen eines Default‑Werts, was bei Dumps und Restores zu Problemen führen kann.
Welche dieser PostgreSQL‑Funktionen ist NICHT ❌ Teil des ANSI‑SQL‑Standards?
Beispiele für PostgreSQL‑Erweiterungen zu ANSI SQL:
RETURNING‑Klausel.ILIKEfür case‑insensitive Vergleiche.- Array‑Typen und -Operationen.
- JSON/JSONB‑Typen.
Der ursprüngliche ANSI‑SQL‑Standard enthält:
WITH(Common Table Expressions).LIKEfür Mustervergleich.LATERAL‑Joins.- Fensterfunktionen.
Außer bei “Hängt von Nebeneffekten ab” Was passiert nach einem Fehler?
BEGIN;UPDATE students SET status = 'alumni' WHERE grade = 12;UPDATE students SET graduation_date = CURRENT_DATE WHERE grade = 12;UPDATE students SET grade = 'GRADUATED'; -- 🚨 Error: type mismatchCOMMIT;Wenn hier ein Fehler auftritt:
- Die gesamte Transaktion wird zurückgerollt
- Es werden keine Änderungen committed
- Die Transaktion wird als fehlgeschlagen markiert
Um teilweise zu committen:
BEGIN;UPDATE ...;SAVEPOINT my_save;UPDATE ...; -- ErrorROLLBACK TO my_save;COMMIT;Welche ON-Bedingung kann PostgreSQL für einen HASH JOIN verwenden?
SELECT *FROM students aJOIN grades bON /* What goes here? ⁉ */;Ein Hash-Join ist mit einer Gleichheitsbedingung (=) im ON‑Clause möglich.
=ist die zentrale Prädikatform für Hash-Joins>und>=sind keine Hash‑Join‑PrädikateHASH JOINist keine gültige Syntax in PostgreSQL
Der Planner kann trotzdem einen Nested‑Loop‑ oder Merge‑Join wählen, abhängig von Tabellengröße, Statistiken, Indizes und Speichereinstellungen.
Welcher Index ist für diese Abfrage besser geeignet?
-- Query:SELECT * FROM studentsWHERE grade_level = 42 AND last_name IN ('Levy', 'Smith');Für mich ist das Überraschende, dass ein mehrspaltiger Index sogar dann verwendet werden kann, wenn die Spaltenreihenfolge im Abfrage‑Text nicht mit der Indexdefinition übereinstimmt.
Note: Bei B‑Tree‑Indizes ist die führende Spalte entscheidend. Da diese Abfrage nach grade_level und last_name filtert, passt ein Index, der mit grade_level beginnt und danach last_name enthält, gut.
Je schneller SQL die wenigsten Zeilen auswählen kann, desto besser ist die Performance.
Zum Beispiel, wenn Sie eine Tabelle task haben und wissen, dass status selektiver ist als created_at, könnten Sie einen Index wählen, der mit status beginnt, für eine Abfrage wie status = 'done' AND created_at > '2024-01-01'. Die Reihenfolge der Bedingungen im Text der WHERE‑Klausel ist nicht entscheidend; wichtig sind die Spaltenreihenfolge des Index und die Form der Prädikate.
Ein B+Tree‑Index kann verwendet werden für:
- Die führende Spalte oder ein linksseitiges Präfix der Spalten.
- Operatoren wie
=,>,<,BETWEENundIN, je nach Abfrageform. - Präfix‑Abgleich,
LIKE 'prefix%'.
Danke an u/mwdb2 für den Hinweis auf einen früheren Fehler in dieser Erklärung!
Was ist korrekt für case-sensitive Spaltennamen?
CREATE TABLE grades ( "Student Name" VARCHAR(100), 'Student Grade' INTEGER);In PostgreSQL:
- Doppelte Anführungszeichen (
") sind für Bezeichner (Tabellennamen, Spaltennamen) - Einfache Anführungszeichen (
') sind für Zeichenkettenliterale
Best Practices:
- Vermeide gemischte Groß‑ und Kleinschreibung oder Leerzeichen in Namen
- Verwende snake_case für Bezeichner
- Verwende zitierte Bezeichner nur, wenn es unbedingt nötig ist
Wie geben Sie einen Spaltennamen mit einem Punkt an?
CREATE TABLE teachers ( id INT GENERATED BY DEFAULT AS IDENTITY, first.name TEXT, -- How do you include the column: first.name? salary NUMERIC);PostgreSQL verwendet doppelte Anführungszeichen für das Quotieren von Bezeichnern:
- Doppelte Anführungszeichen
"..."für Bezeichner (Spaltennamen, Tabellennamen) - Einzelne Anführungszeichen
'...'für Zeichenkettenliterale - Die Form
first.namewird alstable_name.column_nameinterpretiert
Ohne Anführungszeichen würde ein Punkt im Spaltennamen als Trennzeichen für Schema/Tabellen angesehen! Außerdem werden alle nicht quotierten Bezeichner standardmäßig in Kleinbuchstaben umgewandelt.
Um Überraschungen zu vermeiden, sollte man snake_case verwenden und Sonderzeichen meiden.
Welcher Syntax ist gültig, um zufällig 10 % der Studenten zu entnehmen?
Das hier ist knifflig! Es enthält ungefähr 6 Fallen, darunter:
- Hohe‑Level‑Beschreibung + Syntax‑Fragmente. Testet, wie du unvollständige Informationen anpasst und zusammensetzt.
- Erfordert vertrautes Wissen über die
TABLESAMPLE‑Syntax, da keine derTABLESAMPLE‑Optionen die korrekte Syntax verwendet! (Unheimlich! Ich weiß! Weiter so, ich glaube an dich!!! ❤️) - Das
ROW_NUMBER() OVER (ORDER BY RAND())undORDER BY RANDOM() > 10sind weitere falsche Fährten. Sie sehen aus, als könnten sie korrekt sein, sind es aber nicht.RAND()gibt es nicht. UndRANDOM() > 10ist ein boolescher Ausdruck, der immer false ist, weilRANDOM()immer im Bereich0.0‑1.0liegt. Ein weiteres Problem:ORDER BY RANDOM() > 10würde nach einem booleschen Wert sortieren, nicht nach einer Zufallszahl. Aber das> 10wirkt wie ein Prozentsatz, oder? BERNOULLIist gültig,SAMPLETABLEhingegen nicht.WHERE RANDOM() >= 0.1ist ein Trick!RANDOM()liefert einen Wert im Bereich0.0 <= x < 1.0, sodass>= 0.1etwa 90 % der Zeilen zurückgibt, nicht 10 %.
Bezüglich der TABLESAMPLE‑Methode unterstützt PostgreSQL zwei Stichprobenverfahren:
BERNOULLI: Jede Zeile hat gleiche WahrscheinlichkeitSYSTEM: Block‑basiertes Sampling (schneller, aber weniger zufällig)
Um mehr über Sampling zu erfahren, sieh dir diesen Artikel von Render an.
Example:
-- Sample 10% of rowsSELECT * FROM students TABLESAMPLE BERNOULLI (10);
-- For repeatable results, use REPEATABLE:SELECT * FROM studentsTABLESAMPLE BERNOULLI (10) REPEATABLE (42);Ebenfalls erwähnenswert, dass TABLESAMPLE berichten zufolge nicht sehr zufällig ist. Wenn du eine noch zufälligere Stichprobe fester Größe brauchst, erwäge ORDER BY RANDOM() LIMIT 10. Beachte jedoch, dass das 10 Zeilen zurückgibt, nicht 10 %, und bei großen Tabellen langsam sein kann.
Es gibt auch einige Drittanbieter‑Erweiterungen, die bessere zufällige Stichprobenmethoden bieten, aber das liegt hier außerhalb des Rahmens! 😅
Was bewirkt diese Beschwörung?
CREATE INDEX idx_active_studentsON students(last_name)WHERE status = 'active';Dieser Trick heißt Partial Index.
Sie sind nützlich, um Speicherplatz zu sparen und Abfragen zu beschleunigen, wenn typischerweise nur ein Teil der Zeilen abgefragt wird.
Postgres verwendet den Index nur, wenn die Bedingung status = 'active' im Query vorkommt.
Erinnerung: Postgres unterstützt keine „query hints“ wie andere RDBMSs. Der Abfrageplaner entscheidet, wann ein passender Index verwendet wird.
Wie viele Zeilen wird das zurückgeben?
SELECT COUNT(*)FROM studentsWHERE grade = NULL;Ok, das war ein bisschen knifflig. Der Haken ist, dass x = NULL niemals Zeilen matcht und IMMER genau eine Zeile mit einem Count von 0 zurückgibt.
Da NULL ein unbekannter Wert ist, kann er mit nichts verglichen werden, nicht einmal mit sich selbst.
Der richtige Weg, um NULL‑Werte zu prüfen, ist IS NULL.
Beispiel:
postgres=# SELECT count(*) FROM students WHERE age = null;count------- 0(1 row)
postgres=#postgres=# SELECT count(*) FROM students WHERE age is null;count------- 3(1 row)Was macht EXPLAIN ANALYZE bei UPDATE‑Anweisungen?
EXPLAIN ANALYZEUPDATE studentsSET grade = grade + 1WHERE status = 'active';EXPLAIN ANALYZE führt die Abfrage tatsächlich aus! Seien Sie vorsichtig beim Analysieren einer Schreiboperation, insbesondere bei UPDATE, DELETE‑ und INSERT‑Anweisungen. Möglicherweise müssen Sie nach jedem EXPLAIN ANALYZE Aufräumarbeiten durchführen, um reproduzierbare Ergebnisse zu erhalten.
Best Practices:
- Verwenden Sie
EXPLAIN(ohne ANALYZE) für UPDATE/DELETE/INSERT - Packen Sie Änderungen in Transaktionen:
BEGIN;EXPLAIN ANALYZE ...;ROLLBACK;Gut gemacht! Du hast in mehreren Bereichen von PostgreSQL tief gegraben! 🐘
Ich hoffe, du hast etwas Neues gelernt oder zumindest eine Punktzahl, mit der du prahlen kannst! 🏆
Mehr Nervenkitzel gefällig? Sieh dir meine Quiz‑Sammlung für endlosen* Spaß an!