Quiz: Postgres in profondità, parte 2
Sei un duro dell'SQL? O un rammollito?
Parte 2 di 2. Torna alla Parte 1
Benvenuti alla seconda parte del mio Deep Postgres Quiz!
Questo quiz copre un mix di funzionalità familiari e aspetti meno noti di PostgreSQL, oltre a diverse insidie: JOIN, NULL, standard ANSI SQL, transazioni, internals, indicizzazione, campionamento dei dati… e molto altro!
In bocca al lupo! 🍀
Quale non è ❌ un’espressione JOIN valida in PostgreSQL?
Sapevi dell’esistenza di CROSS JOIN, vero?
Il JOIN ALL ti ha fatto pensare a un’altra operazione, UNION ALL?
La risposta corretta qui è JOIN ALL ❌.
I tipi di JOIN validi sono:
INNER JOIN(il JOIN predefinito)LEFT JOIN(oLEFT OUTER JOIN)RIGHT JOIN(oRIGHT OUTER JOIN)FULL JOIN(oFULL OUTER JOIN)CROSS JOIN(il prodotto cartesiano, a meno che una clausolaWHEREsuccessiva non lo filtri)
Quale condizione ON può utilizzare PostgreSQL per un HASH JOIN?
SELECT *FROM students aJOIN grades bON /* What goes here? ⁉ */;Un hash join è possibile con una condizione di uguaglianza (=) nella clausola ON.
=è la forma del predicato chiave per gli hash join>e>=non sono predicati per hash joinHASH JOINnon è una sintassi valida in PostgreSQL
Il planner potrebbe comunque scegliere un nested loop o un merge join a seconda delle dimensioni della tabella, delle statistiche, degli indici e delle impostazioni della memoria.
Qual è la sintassi corretta per i nomi delle colonne case-sensitive?
CREATE TABLE grades ( "Student Name" VARCHAR(100), 'Student Grade' INTEGER);In PostgreSQL:
- Le virgolette doppie (
") si usano per gli identificatori (nomi di tabelle, nomi di colonne) - Le virgolette singole (
') si usano per le stringhe letterali
Best practice:
- Evita l’uso di maiuscole/minuscole miste o spazi nei nomi
- Usa lo snake_case per gli identificatori
- Usa gli identificatori tra virgolette solo quando è assolutamente necessario
Come si specifica un nome di colonna che contiene un punto?
CREATE TABLE teachers ( id INT GENERATED BY DEFAULT AS IDENTITY, first.name TEXT, -- How do you include the column: first.name? salary NUMERIC);PostgreSQL utilizza i doppi apici per il quoting degli identificatori:
- Doppi apici
"..."per gli identificatori (nomi di colonne, nomi di tabelle) - Singoli apici
'...'per le stringhe letterali - La forma
first.nameviene interpretata comenome_tabella.nome_colonna
Senza virgolette, un punto nel nome di una colonna verrebbe interpretato come un separatore schema/tabella! Inoltre, tutti gli identificatori non virgolettati vengono convertiti in minuscolo per impostazione predefinita.
Per ridurre le sorprese, è meglio usare lo snake_case ed evitare l’uso di caratteri speciali.
Qual è la sintassi valida per campionare casualmente il 10% degli studenti?
Questa è difficile! Contiene circa 6 trappole, tra cui:
- Descrizione di alto livello + frammenti di sintassi. Mette alla prova come adatti e assembli informazioni incomplete.
- Richiede una conoscenza approfondita della sintassi di
TABLESAMPLE, poiché nessuna delle opzioniTABLESAMPLEutilizza la sintassi corretta! (Sinistro, lo so! Continua così, credo in te!!! ❤️) ROW_NUMBER() OVER (ORDER BY RAND())eORDER BY RANDOM() > 10sono ulteriori depistaggi. Sembrano corretti, ma non lo sono.RAND()non esiste. ERANDOM() > 10è un’espressione booleana che sarà sempre falsa poichéRANDOM()restituisce sempre un valore nell’intervallo0.0-1.0. Un altro problema:ORDER BY RANDOM() > 10ordinerebbe in base a un valore booleano, non a un numero casuale. Ma quel> 10sembrava proprio una percentuale, vero?BERNOULLIè valido, tuttaviaSAMPLETABLEnon lo è.WHERE RANDOM() >= 0.1è un trucco!RANDOM()restituisce un valore nell’intervallo0.0 <= x < 1.0, quindi>= 0.1restituirebbe circa il 90% delle righe, non il 10%.
Per quanto riguarda il metodo TABLESAMPLE, PostgreSQL supporta due metodi di campionamento:
BERNOULLI: Ogni riga ha la stessa probabilità.SYSTEM: Campionamento a livello di blocco (più veloce ma meno casuale).
Per saperne di più sul campionamento, consulta questo articolo di Render.
Esempio:
-- Sample 10% of rowsSELECT * FROM students TABLESAMPLE BERNOULLI (10);
-- For repeatable results, use REPEATABLE:SELECT * FROM studentsTABLESAMPLE BERNOULLI (10) REPEATABLE (42);Vale anche la pena menzionare che TABLESAMPLE è stato segnalato per non essere molto casuale. Se hai bisogno di un campione di dimensioni fisse più casuale, considera l’uso di ORDER BY RANDOM() LIMIT 10. Ma tieni presente che questo restituisce 10 righe, non il 10%, e può essere lento su tabelle di grandi dimensioni.
Esistono anche alcune estensioni di terze parti che forniscono metodi di campionamento casuale migliori, ma questo va oltre lo scopo di questa sfida! 😅
Cosa fa questo incantesimo?
CREATE INDEX idx_active_studentsON students(last_name)WHERE status = 'active';Questo trucco è chiamato Partial Index (Indice Parziale).
Sono utili per ridurre l’uso del disco e velocizzare le query quando viene interrogato tipicamente solo un sottoinsieme di righe.
Il planner può considerare l’indice quando riesce a dimostrare che il predicato della query implica status = 'active'. Non serve necessariamente lo stesso testo, ma il riconoscimento ha limiti. L’idoneità non garantisce che l’indice venga scelto.
Promemoria: Postgres non supporta le ‘query hints’ come altri RDBMS. Il query planner deciderà autonomamente quando utilizzare gli indici appropriati.
Cosa fa EXPLAIN ANALYZE per le istruzioni UPDATE?
EXPLAIN ANALYZEUPDATE studentsSET grade = grade + 1WHERE status = 'active';EXPLAIN ANALYZE esegue effettivamente la query! Fai attenzione quando analizzi un’operazione di scrittura, nello specifico le istruzioni UPDATE, DELETE e INSERT. Potresti dover eseguire operazioni di pulizia dopo ogni EXPLAIN ANALYZE per ottenere risultati ripetibili.
Best practice:
- Usa
EXPLAIN(senza ANALYZE) per UPDATE/DELETE/INSERT - Avvolgi le modifiche in transazioni:
BEGIN;EXPLAIN ANALYZE ...;ROLLBACK;Ottimo lavoro! Hai approfondito diversi aspetti di PostgreSQL! 🐘
Spero che tu abbia imparato qualcosa di nuovo, o che almeno tu abbia ottenuto un punteggio di cui vantarti! 🏆
Vuoi altre emozioni forti? Dai un’occhiata alla mia Quiz Collection per un divertimento infinito*!
