Menu

Database Technologies Topic

PostgreSQL Databases & Schemas

A. Databases vs Schemas

Conceptual Hierarchy

text

PostgreSQL Instance (Cluster)
│
├── Database 1 (myapp)
│   ├── Schema 1 (public) - Default
│   │   ├── Table 1 (users)
│   │   ├── Table 2 (orders)
│   │   └── View 1 (active_users)
│   │
│   ├── Schema 2 (analytics)
│   │   ├── Table 1 (user_stats)
│   │   └── Materialized View 1 (daily_metrics)
│   │
│   └── Schema 3 (staging)
│       └── Table 1 (temp_data)
│
└── Database 2 (reports)
    ├── Schema public
    └── Schema archive

Key Differences

Aspect Database Schema
Isolation High - Separate connections required Low - Accessible within same database
Cross-access Not directly possible (use FDW) Directly accessible
Backup Can be backed up individually Backed up as part of database
Users/Roles Can have different owners Same users across schemas
Use Case Completely separate applications Logical separation within same app

B. Creating / Dropping Databases

1. Creating Databases

sql

-- Basic database creation
CREATE DATABASE mydb;

-- With specific owner
CREATE DATABASE mydb OWNER = alice;

-- With template (clone existing database)
CREATE DATABASE mydb_copy TEMPLATE = mydb;

-- With encoding and collation
CREATE DATABASE mydb
    ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.UTF-8'
    LC_CTYPE = 'en_US.UTF-8'
    TEMPLATE = template0;  -- Use clean template

-- With connection limit
CREATE DATABASE mydb 
    CONNECTION LIMIT = 50;  -- Max 50 concurrent connections

2. Using Template Databases

sql

-- List existing databases (including templates)
\l

-- Create database from template1 (default, includes standard extensions)
CREATE DATABASE db_from_template1 TEMPLATE template1;

-- Create clean database from template0 (empty, no extensions)
CREATE DATABASE clean_db TEMPLATE template0;

-- Cannot copy database if there are active connections
-- Force close connections first:
SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = 'source_db';

3. Dropping Databases

sql

-- Basic drop
DROP DATABASE mydb;

-- Drop if exists (prevents error)
DROP DATABASE IF EXISTS mydb;

-- Drop with force (terminate connections first)
-- In one transaction:
SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = 'mydb';
DROP DATABASE mydb;

4. Managing Databases via Command Line

bash

# Create database from terminal
createdb -h localhost -p 5432 -U postgres mydb

# Drop database from terminal
dropdb -h localhost -p 5432 -U postgres mydb

# With specific options
createdb -E UTF8 --locale=en_US.UTF-8 -T template0 mydb

# List all databases
psql -h localhost -U postgres -c "\l"

5. Database Properties & Modifications

sql

-- Alter database
ALTER DATABASE mydb RENAME TO newname;
ALTER DATABASE mydb OWNER TO new_owner;
ALTER DATABASE mydb SET enable_indexscan = off;  -- Per-database setting

-- Change connection limit
ALTER DATABASE mydb CONNECTION LIMIT 100;

-- Reset to default
ALTER DATABASE mydb RESET connection_limit;

-- View database information
SELECT * FROM pg_database WHERE datname = 'mydb';

-- Size of database
SELECT pg_size_pretty(pg_database_size('mydb')) as size;

C. Using Schemas

1. Default public Schema

sql

-- Every database has a 'public' schema by default
-- Objects created without specifying schema go here

CREATE TABLE users (id SERIAL, name TEXT);  -- Goes to public.users
-- Equivalent to:
CREATE TABLE public.users (id SERIAL, name TEXT);

2. Creating Custom Schemas

sql

-- Basic schema creation
CREATE SCHEMA analytics;

-- With authorization
CREATE SCHEMA analytics AUTHORIZATION alice;

-- Create schema if not exists (PostgreSQL 9.3+)
CREATE SCHEMA IF NOT EXISTS staging;

-- Create and set search path
CREATE SCHEMA app_schema;
SET search_path TO app_schema, public;

3. Schema Operations

sql

-- Create objects in specific schema
CREATE TABLE analytics.user_metrics (
    id SERIAL PRIMARY KEY,
    metric_date DATE,
    value NUMERIC
);

-- View all schemas in current database
\dn  -- psql command
SELECT schema_name FROM information_schema.schemata;

-- Drop schema
DROP SCHEMA analytics;
DROP SCHEMA analytics CASCADE;  -- Drop all objects in schema too

-- Rename schema
ALTER SCHEMA analytics RENAME TO business_intel;

-- Change owner
ALTER SCHEMA business_intel OWNER TO data_team;

4. Practical Schema Use Cases

sql

-- 1. Multi-tenant architecture (one schema per tenant)
CREATE SCHEMA tenant_a;
CREATE SCHEMA tenant_b;

-- Same table structure in each schema
CREATE TABLE tenant_a.customers (...);
CREATE TABLE tenant_b.customers (...);

-- 2. Separation by function
CREATE SCHEMA app;
CREATE SCHEMA reporting;
CREATE SCHEMA audit;

-- 3. Version management
CREATE SCHEMA v1;
CREATE SCHEMA v2;
-- Migrate data between schemas for version upgrades

D. Search Path

1. Understanding Search Path

sql

-- Current search path
SHOW search_path;
-- Default: "$user", public

-- What it means:
-- 1. Look in schema with current user's name
-- 2. Look in 'public' schema
-- 3. If not found, error

-- Set search path for session
SET search_path TO analytics, public;

-- Set for specific user/role
ALTER ROLE alice SET search_path = 'app_schema, public';

-- Set for database
ALTER DATABASE mydb SET search_path = 'core, public, "$user"';

2. Search Path Examples

sql

-- Default behavior
SET search_path TO public;
CREATE TABLE test (id INT);  -- Creates public.test

-- With custom schema first
SET search_path TO app, public;
CREATE TABLE test (id INT);  -- Creates app.test

SELECT * FROM test;  -- Looks in app.test first, then public.test

-- Explicit reference always works
SELECT * FROM public.test;  -- Explicit schema
SELECT * FROM app.test;     -- Explicit schema

3. Schema-Specific Operations

sql

-- Move table between schemas
ALTER TABLE public.users SET SCHEMA app;

-- Grant permissions on schema
GRANT USAGE ON SCHEMA analytics TO reader_role;
GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO reader_role;

-- Revoke from public schema (security best practice)
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON DATABASE mydb FROM PUBLIC;

4. Information Schema Views

sql

-- Find all tables in specific schema
SELECT table_name 
FROM information_schema.tables 
WHERE table_schema = 'analytics';

-- Find all functions in schema
SELECT routine_name
FROM information_schema.routines
WHERE specific_schema = 'app';

-- List schemas with their owners
SELECT s.nspname as schema_name, 
       u.usename as owner
FROM pg_catalog.pg_namespace s
JOIN pg_catalog.pg_user u ON u.usesysid = s.nspowner;

5. Best Practices

sql

-- 1. Remove public schema CREATE privileges (security)
REVOKE CREATE ON SCHEMA public FROM PUBLIC;

-- 2. Use schemas for logical separation
CREATE SCHEMA core;
CREATE SCHEMA staging;
CREATE SCHEMA reporting;

-- 3. Set appropriate search paths per role
ALTER ROLE app_user SET search_path = 'core, public';
ALTER ROLE analyst SET search_path = 'reporting, core, public';

-- 4. Use qualified names in applications
-- Instead of: SELECT * FROM users
-- Use: SELECT * FROM core.users

-- 5. Consider schema-based multi-tenancy vs row-based
-- Schema-based: Better isolation, easier backup per tenant
-- Row-based: Simpler queries, less overhead

6. Common Patterns

sql

-- Pattern 1: Application modules
CREATE SCHEMA auth;
CREATE SCHEMA billing;
CREATE SCHEMA inventory;

-- Pattern 2: Temporal separation
CREATE SCHEMA current_data;
CREATE SCHEMA archive_2023;
CREATE SCHEMA archive_2024;

-- Pattern 3: Testing/development
CREATE SCHEMA dev;
CREATE SCHEMA test;
CREATE SCHEMA prod;  -- Or use separate databases for prod

-- Pattern 4: Third-party extensions
-- Extensions often create their own schemas
CREATE EXTENSION postgis;  -- Creates postgis schema
CREATE EXTENSION uuid-ossp;  -- Creates functions in public

This structure allows for clean separation of concerns while maintaining the ability to join data across schemas when needed. Remember that schemas are primarily a logical separation mechanism, not a physical one.

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?