Database Technologies Topic
PostgreSQL Advanced Concepts
A. Advanced Data Types
JSONB (Binary JSON with indexing)
Explanation: JSONB stores JSON data in a binary format that supports indexing and efficient querying. Better than JSON type for most use cases.
sql
-- Create table with JSONB
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
attributes JSONB,
tags JSONB
);
-- Insert JSON data
INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"brand": "Dell", "ram": 16, "ports": ["USB-C", "HDMI"]}');
-- Query JSONB (-> and ->> operators)
SELECT name, attributes->'brand' as brand FROM products;
SELECT name, attributes->>'brand' as brand_text FROM products;
-- Check existence
SELECT * FROM products WHERE attributes ? 'brand';
-- JSONB indexing (GIN index)
CREATE INDEX idx_gin_attributes ON products USING GIN (attributes);
Arrays & Array Operators
Explanation: PostgreSQL supports arrays of any data type with rich operator support.
sql
-- Create table with arrays
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
email TEXT[],
scores INTEGER[],
schedule TEXT[][]
);
-- Insert array data
INSERT INTO users (name, email, scores)
VALUES ('John', ARRAY['john@email.com', 'john@work.com'], ARRAY[85, 92, 78]);
-- Query arrays
SELECT * FROM users WHERE 'john@work.com' = ANY(email);
SELECT * FROM users WHERE scores @> ARRAY[85]; -- Contains 85
SELECT name, array_length(scores, 1) as score_count FROM users;
-- Array functions
SELECT array_append(scores, 95) FROM users;
SELECT unnest(scores) as individual_score FROM users;
ENUM
Explanation: Custom enumerated type with fixed set of values, better than text for constrained values.
sql
-- Create ENUM type
CREATE TYPE user_status AS ENUM ('active', 'inactive', 'pending', 'banned');
-- Use ENUM in table
CREATE TABLE users_enum (
id SERIAL PRIMARY KEY,
name TEXT,
status user_status DEFAULT 'pending'
);
-- Insert with ENUM
INSERT INTO users_enum (name, status) VALUES ('Alice', 'active');
-- Benefits: Type safety, ordering, efficient storage
HSTORE
Explanation: Key-value store within PostgreSQL for simple key-value pairs.
sql
-- Enable hstore extension
CREATE EXTENSION IF NOT EXISTS hstore;
-- Create table with hstore
CREATE TABLE product_hstore (
id SERIAL PRIMARY KEY,
name TEXT,
properties HSTORE
);
-- Insert data
INSERT INTO product_hstore (name, properties)
VALUES ('Phone', 'color=>"black", storage=>"256GB", weight=>"200g"');
-- Query hstore
SELECT * FROM product_hstore WHERE properties -> 'color' = 'black';
SELECT name, properties -> 'storage' as storage FROM product_hstore;
Range Types
Explanation: Represents a range of values (dates, numbers, timestamps) with inclusive/exclusive bounds.
sql
-- Date range
CREATE TABLE bookings (
id SERIAL PRIMARY KEY,
room TEXT,
reservation DATERANGE,
EXCLUDE USING GIST (room WITH =, reservation WITH &&) -- Prevent overlaps
);
-- Insert ranges
INSERT INTO bookings (room, reservation)
VALUES ('101', '[2024-01-01, 2024-01-05)');
-- Query ranges
SELECT * FROM bookings WHERE reservation @> DATE '2024-01-02';
SELECT * FROM bookings WHERE reservation && '[2024-01-03, 2024-01-07)';
-- Range operators: @> (contains), <@ (contained by), && (overlaps)
B. Functions & Expressions
Built-in Functions
Explanation: PostgreSQL provides extensive built-in functions for data manipulation.
sql
-- Math functions
SELECT ROUND(123.456, 2), CEIL(123.1), FLOOR(123.9), ABS(-100);
-- Aggregate functions
SELECT array_agg(name) as all_names, string_agg(name, ', ') as csv_names
FROM employees;
-- Window functions
SELECT name, salary, RANK() OVER (ORDER BY salary DESC) as salary_rank
FROM employees;
-- System functions
SELECT VERSION(), CURRENT_USER, CURRENT_TIMESTAMP, txid_current();
Conditional Logic (CASE)
Explanation: SQL's IF-THEN-ELSE statement for conditional logic in queries.
sql
-- Simple CASE
SELECT name, salary,
CASE
WHEN salary > 100000 THEN 'High'
WHEN salary > 50000 THEN 'Medium'
ELSE 'Low'
END as salary_level
FROM employees;
-- Searched CASE in aggregate
SELECT
department,
COUNT(*) as total,
SUM(CASE WHEN salary > 100000 THEN 1 ELSE 0 END) as high_earners,
AVG(CASE WHEN gender = 'M' THEN salary END) as avg_male_salary
FROM employees
GROUP BY department;
-- NULL handling with COALESCE
SELECT name, COALESCE(bonus, 0) as bonus_or_zero FROM employees;
String & Date Functions
Explanation: Powerful functions for string and date manipulation.
sql
-- String functions
SELECT
UPPER(name) as upper_name,
LOWER(name) as lower_name,
LENGTH(name) as name_length,
SUBSTRING(name FROM 1 FOR 3) as first_3_chars,
REPLACE(name, ' ', '_') as name_no_spaces,
CONCAT(first_name, ' ', last_name) as full_name
FROM employees;
-- Date functions
SELECT
CURRENT_DATE as today,
CURRENT_TIMESTAMP as now,
AGE('2024-12-31', CURRENT_DATE) as time_until_eoy,
EXTRACT(YEAR FROM hire_date) as hire_year,
DATE_TRUNC('month', hire_date) as hire_month,
hire_date + INTERVAL '1 year' as anniversary
FROM employees;
C. Views
Views
Explanation: Virtual tables based on SQL queries. Data is not stored separately.
sql
-- Create view CREATE OR REPLACE VIEW active_employees AS SELECT id, name, department, salary FROM employees WHERE is_active = true AND termination_date IS NULL; -- Use view like a table SELECT * FROM active_employees WHERE department = 'Engineering'; -- Updateable view (if simple enough) UPDATE active_employees SET salary = salary * 1.05; -- View with check option CREATE VIEW high_paid_employees AS SELECT * FROM employees WHERE salary > 100000 WITH CHECK OPTION; -- Prevents inserts that don't satisfy WHERE
Materialized Views
Explanation: Physical snapshot of query results that can be refreshed periodically. Faster but stale data.
sql
-- Create materialized view
CREATE MATERIALIZED VIEW department_stats AS
SELECT
department,
COUNT(*) as employee_count,
AVG(salary) as avg_salary,
SUM(salary) as total_salary
FROM employees
GROUP BY department;
-- Query materialized view (fast)
SELECT * FROM department_stats ORDER BY avg_salary DESC;
-- Refresh strategies
REFRESH MATERIALIZED VIEW department_stats; -- Full refresh
REFRESH MATERIALIZED VIEW CONCURRENTLY department_stats; -- Concurrent (PostgreSQL 9.4+)
-- Add indexes to materialized views
CREATE UNIQUE INDEX idx_dept_stats ON department_stats (department);
Refresh Strategies
Explanation: When and how to refresh materialized views.
sql
-- Manual refresh
REFRESH MATERIALIZED VIEW sales_summary;
-- Scheduled via cron/pgAgent
-- */5 * * * * psql -c "REFRESH MATERIALIZED VIEW hourly_stats"
-- Trigger-based refresh (example)
CREATE OR REPLACE FUNCTION refresh_mv_on_employee_change()
RETURNS TRIGGER AS $$
BEGIN
REFRESH MATERIALIZED VIEW CONCURRENTLY department_stats;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- Note: PostgreSQL doesn't have automatic refresh built-in
D. Transactions
BEGIN, COMMIT, ROLLBACK
Explanation: ACID transaction control - group operations as atomic units.
sql
-- Start transaction
BEGIN;
-- Multiple operations
INSERT INTO accounts (name, balance) VALUES ('Alice', 1000);
UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';
-- Either commit or rollback
COMMIT; -- Save all changes
-- OR
ROLLBACK; -- Discard all changes since BEGIN
-- Savepoints within transactions
BEGIN;
INSERT INTO table1 VALUES (1);
SAVEPOINT my_savepoint;
INSERT INTO table1 VALUES (2);
ROLLBACK TO my_savepoint; -- Undo only second insert
COMMIT; -- First insert remains
ACID Properties
Explanation: Four guarantees for reliable transactions.
sql
-- Atomicity: All or nothing BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- Both succeed or both fail COMMIT; -- Consistency: Database rules maintained BEGIN; -- Foreign key constraints, unique constraints, check constraints -- are validated at COMMIT COMMIT; -- Isolation: Concurrent transactions don't interfere -- Set via: SET TRANSACTION ISOLATION LEVEL ... -- Durability: Committed changes survive crashes -- PostgreSQL WAL (Write Ahead Logging) ensures this
Isolation Levels
Explanation: Control how transaction isolation is enforced.
sql
-- Set isolation level per transaction BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; -- Or SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Four levels in PostgreSQL: -- 1. READ UNCOMMITTED (treated as READ COMMITTED in PostgreSQL) -- 2. READ COMMITTED (default) - See only committed data -- 3. REPEATABLE READ - Snapshot at transaction start -- 4. SERIALIZABLE - Full serialization, most strict -- Example: Prevent non-repeatable reads BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT balance FROM accounts WHERE id = 1; -- Returns 1000 -- Another transaction updates balance to 900 SELECT balance FROM accounts WHERE id = 1; -- Still returns 1000 COMMIT;
MVCC (Multi-Version Concurrency Control) ⭐
Explanation: PostgreSQL's core mechanism for handling concurrent access without locking.
sql
-- Each row has system columns
SELECT xmin, xmax, ctid, * FROM employees LIMIT 1;
-- xmin: Transaction ID that created the row
-- xmax: Transaction ID that deleted/updated the row (or 0)
-- ctid: Physical location of the row
-- How MVCC works:
-- 1. UPDATE creates new row version, marks old with xmax
-- 2. DELETE marks row with xmax
-- 3. Each transaction sees snapshot at start time
-- Check transaction IDs
SELECT txid_current(), pg_backend_pid();
-- Monitor MVCC bloat
SELECT
schemaname, tablename,
n_dead_tup as dead_rows,
n_live_tup as live_rows
FROM pg_stat_user_tables;
-- Clean up dead rows (VACUUM)
VACUUM ANALYZE employees; -- Manual cleanup
-- Or enable autovacuum (default)
-- Transaction visibility example
-- Transaction A:
BEGIN;
UPDATE employees SET salary = 50000 WHERE id = 1;
-- Row is marked with xmax for other transactions
-- Transaction B sees old value until A commits
Key MVCC Benefits:
-
Readers don't block writers
-
Writers don't block readers
-
No dirty reads possible
-
Automatic snapshot isolation
MVCC Trade-offs:
-
Table bloat from old row versions
-
Need for VACUUM maintenance
-
Transaction ID wraparound risk
Comments (0)
No comments yet. Be the first to comment!