Yugabyte Structured Query Language (YSQL) is a fully-relational, ANSI SQL-compliant API that is best fit for scale-out RDBMS applications requiring ultra resilience, massive write scalability, and geographic data distribution.
-- Create a databaseCREATE DATABASE myapp;-- Create a table with primary keyCREATE TABLE users ( id SERIAL PRIMARY KEY, username TEXT NOT NULL UNIQUE, email TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW());-- Create an indexCREATE INDEX idx_users_email ON users(email);-- Add a foreign key constraintCREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), total DECIMAL(10, 2), created_at TIMESTAMP DEFAULT NOW());
BEGIN;-- Deduct from accountUPDATE accounts SET balance = balance - 100 WHERE id = 1;-- Add to another accountUPDATE accounts SET balance = balance + 100 WHERE id = 2;-- Record the transferINSERT INTO transfers (from_account, to_account, amount) VALUES (1, 2, 100);COMMIT;
Transaction Isolation Levels:
READ COMMITTED (default)
REPEATABLE READ
SERIALIZABLE
-- Set transaction isolation levelSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
YSQL supports various index types for query optimization:
-- Standard indexCREATE INDEX idx_users_username ON users(username);-- Composite indexCREATE INDEX idx_orders_user_date ON orders(user_id, created_at);-- Unique indexCREATE UNIQUE INDEX idx_users_email ON users(email);
-- Create a functionCREATE OR REPLACE FUNCTION get_user_order_count(user_id INTEGER)RETURNS INTEGER AS $$DECLARE count INTEGER;BEGIN SELECT COUNT(*) INTO count FROM orders WHERE orders.user_id = user_id; RETURN count;END;$$ LANGUAGE plpgsql;-- Use the functionSELECT username, get_user_order_count(id) as order_countFROM users;
-- Create trigger functionCREATE OR REPLACE FUNCTION update_modified_timestamp()RETURNS TRIGGER AS $$BEGIN NEW.updated_at = NOW(); RETURN NEW;END;$$ LANGUAGE plpgsql;-- Create triggerCREATE TRIGGER trigger_update_user_timestampBEFORE UPDATE ON usersFOR EACH ROWEXECUTE FUNCTION update_modified_timestamp();
-- Create a viewCREATE VIEW user_order_summary ASSELECT u.id, u.username, COUNT(o.id) as total_orders, COALESCE(SUM(o.total), 0) as total_spentFROM users uLEFT JOIN orders o ON u.id = o.user_idGROUP BY u.id, u.username;-- Query the viewSELECT * FROM user_order_summary WHERE total_orders > 5;
WITH monthly_sales AS ( SELECT DATE_TRUNC('month', created_at) as month, SUM(total) as sales FROM orders GROUP BY DATE_TRUNC('month', created_at))SELECT month, sales, LAG(sales) OVER (ORDER BY month) as previous_month_salesFROM monthly_salesORDER BY month;
-- Create a colocated databaseCREATE DATABASE myapp WITH COLOCATION = true;-- Create colocated tableCREATE TABLE small_reference_table ( id SERIAL PRIMARY KEY, name TEXT) WITH (COLOCATION = true);
-- Window functionsSELECT username, created_at, ROW_NUMBER() OVER (ORDER BY created_at) as user_number, DENSE_RANK() OVER (ORDER BY DATE(created_at)) as day_rankFROM users;-- Recursive CTEWITH RECURSIVE subordinates AS ( SELECT employee_id, manager_id, name FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.employee_id, e.manager_id, e.name FROM employees e INNER JOIN subordinates s ON s.employee_id = e.manager_id)SELECT * FROM subordinates;
-- Good: HASH partitioning for even distributionCREATE TABLE users ( id INTEGER PRIMARY KEY) SPLIT INTO 16 TABLETS;-- For sequential IDs, use HASHCREATE TABLE orders ( id SERIAL, PRIMARY KEY (id HASH));
Leverage Indexes
Create indexes for frequently queried columns:
Use covering indexes to avoid table lookups
Create partial indexes for filtered queries
Monitor index usage with EXPLAIN
Optimize Transactions
Keep transactions short
Use appropriate isolation levels
Leverage RETURNING clause for single-statement transactions
-- Single statement with RETURNINGUPDATE accounts SET balance = balance - 100WHERE id = 1RETURNING balance;
Use Prepared Statements
Prepared statements improve performance and security:
PREPARE get_user AS SELECT * FROM users WHERE id = $1;EXECUTE get_user(123);