Design Process
Design Process
A systematic approach to schema design involves five key steps:
Identify entities: What are the main things the system tracks? For an e-commerce app: Customers, Products, Orders, Reviews.
Define attributes: What properties does each entity have? A customer has a name, email, and address. A product has a name, price, and category.
Establish relationships: How do entities relate? A customer places many orders. An order contains many products. A customer writes many reviews.
Choose primary keys: Each table needs a unique identifier. Use auto-incrementing integers or UUIDs.
Define constraints: Add NOT NULL, UNIQUE, DEFAULT, and CHECK constraints to enforce data integrity.
-- Step 1-2: Entities and attributes
-- Customers entity
CREATE TABLE customers (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Step 3: Relationships defined via foreign keys
-- An order belongs to one customer
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT NOT NULL,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'pending',
total_amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
Iterate on the design. Start simple, then add complexity as requirements evolve. Avoid over-engineering the initial schema.
Real-World Example: E-Commerce Schema
Real-World Example: E-Commerce Schema
Here is a complete schema for an e-commerce application covering users, products, orders, and reviews.
-- Customers table
CREATE TABLE customers (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
phone VARCHAR(20),
address_line1 VARCHAR(200),
address_line2 VARCHAR(200),
city VARCHAR(100),
state VARCHAR(50),
zip_code VARCHAR(10),
country VARCHAR(50) DEFAULT 'US',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- Product categories
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
category_name VARCHAR(100) NOT NULL UNIQUE,
parent_category_id INT,
FOREIGN KEY (parent_category_id) REFERENCES categories(category_id)
);
-- Products table
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10,2) NOT NULL,
category_id INT NOT NULL,
stock_quantity INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(category_id)
);
-- Orders table
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT NOT NULL,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
shipping_address TEXT,
total_amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
-- Order items (junction table for orders and products)
CREATE TABLE order_items (
order_item_id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL DEFAULT 1,
unit_price DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- Reviews table
CREATE TABLE reviews (
review_id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL,
customer_id INT NOT NULL,
rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),
title VARCHAR(200),
review_text TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
UNIQUE (product_id, customer_id)
);
This schema handles:
- One customer has many orders
- One order has many items
- One product can be in many orders
- One customer can review many products
- Categories support hierarchy via parent_category_id
Choosing Data Types
Choosing Data Types
Choosing the right data type affects storage, performance, and data integrity. Use the smallest type that safely holds your data.
Integer types:
-- Use appropriate integer sizes
tinyint -- 1 byte, -128 to 127 (flags, small counts)
smallint -- 2 bytes, -32768 to 32767 (status codes, categories)
int -- 4 bytes, standard primary keys
bigint -- 8 bytes, very large datasets or IDs
String types:
varchar(100) -- variable length, use when max length varies (names, emails)
char(2) -- fixed length, use for codes (state abbreviations, country codes)
text -- large text, use for descriptions and reviews
Decimal types:
decimal(10,2) -- exact precision, use for money (up to 99999999.99)
float -- approximate, use for scientific calculations
real -- approximate, single precision
Date and time types:
date -- date only (2025-01-15)
time -- time only (14:30:00)
datetime -- date and time
timestamp -- date and time with timezone awareness
Boolean type:
boolean -- TRUE/FALSE values (is_active, is_deleted)
Best practices:
- Use VARCHAR with appropriate max length, not TEXT when possible
- Use DECIMAL for money, never FLOAT
- Use TIMESTAMP for audit columns (created_at, updated_at)
- Use ENUM for fixed sets of values (status, type)
- Avoid storing large text in main query tables; use separate tables
Naming Conventions
Naming Conventions
Consistent naming conventions make schemas readable and maintainable. Follow these standards:
Tables:
- Use plural nouns: customers, orders, products
- Use snake_case: order_items, not OrderItems
- Use descriptive names: customer_addresses, not addresses
-- Good table names
customers
order_items
product_categories
user_sessions
-- Bad table names
customer (singular)
OrderItems (camelCase)
t1 (meaningless)
Columns:
- Use snake_case: first_name, not FirstName
- Primary keys: table_name_id (customer_id, order_id)
- Foreign keys: referenced_table_id (customer_id in orders)
- Boolean flags: is_active, has_subscription, was_shipped
- Timestamps: created_at, updated_at, deleted_at
-- Good column names
first_name
order_date
total_amount
is_active
created_at
-- Bad column names
firstName
date
total
active
Constraints:
- Primary keys: pk_tablename (pk_customers)
- Foreign keys: fk_tablename_referenced (fk_orders_customers)
- Unique constraints: uk_tablename_column (uk_customers_email)
-- Named constraints
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers
FOREIGN KEY (customer_id) REFERENCES customers(customer_id);
ALTER TABLE customers
ADD CONSTRAINT uk_customers_email
UNIQUE (email);
Indexes:
- Primary key indexes: automatically named after the primary key
- Index naming: idx_tablename_column (idx_orders_customer_id)
Consistent naming prevents confusion when working with large schemas and multiple team members.
Practice Problems
Write SQL queries demonstrating SQL Schema Design. Include examples with different data patterns.
Solution
-- SQL Schema Design query examples
-- 1. Basic usage
-- 2. With NULL handling
-- 3. With GROUP BY
-- 4. With subqueriesOptimize queries using SQL Schema Design for large datasets. Consider indexing and execution plans.
Solution
-- Optimization steps:
-- 1. EXPLAIN ANALYZE
-- 2. Add covering indexes
-- 3. Rewrite subqueries as JOINs
-- 4. Use CTEs for readabilityPractice common interview questions about SQL Schema Design. Explain the concepts clearly.
Solution
-- Interview answers:
-- 1. Definition and purpose
-- 2. Use cases with examples
-- 3. Performance characteristics
-- 4. Common mistakes
-- 5. Alternatives and trade-offsQuiz
1. What is the first step in designing a database schema?
2. Which data type should you use for storing monetary values?
3. What is the convention for naming foreign key columns?
4. What is the primary purpose of SQL Schema Design?
Flashcards
Question
What are the 5 steps of schema design?
Click to reveal answer
Answer
1) Identify entities, 2) Define attributes, 3) Establish relationships, 4) Choose primary keys, 5) Define constraints.
Question
Why use DECIMAL instead of FLOAT for money?
Click to reveal answer
Answer
DECIMAL stores exact values with no rounding errors. FLOAT uses approximate binary representation which can cause small errors that compound in financial calculations.
Question
What naming convention should tables follow?
Click to reveal answer
Answer
Use plural nouns in snake_case: customers, order_items, product_categories. Avoid singular names, camelCase, or meaningless abbreviations.
Question
What is SQL Schema Design?
Click to reveal answer
Answer
SQL Schema Design is a key concept in SQL databases.
Question
When to use SQL Schema Design?
Click to reveal answer
Answer
Use SQL Schema Design when building production systems that require reliability, scalability, and maintainability.
Revision Notes
Key Takeaways
- 1.Follow a systematic 5-step process for schema design
- 2.Choose DECIMAL for money, VARCHAR for strings, TIMESTAMP for dates
- 3.Use plural snake_case for tables, snake_case for columns
- 4.Name foreign keys after the referenced table_id
Interview Tips
- •Walk through designing a schema for a real application step by step
- •Explain why you chose specific data types
- •Discuss how to handle many-to-many relationships with junction tables
- •Mention naming conventions and why consistency matters
Cheat Sheet
Schema Design Cheat Sheet
Design Process
- Identify entities
- Define attributes
- Establish relationships
- Choose primary keys
- Define constraints
Data Type Rules
- Money: DECIMAL(10,2)
- IDs: INT or BIGINT
- Names: VARCHAR(n) with appropriate length
- Text: TEXT for long content
- Flags: BOOLEAN
- Dates: TIMESTAMP for audit columns
Naming Conventions
- Tables: plural, snake_case (customers, order_items)
- Columns: snake_case (first_name, order_date)
- PKs: table_id (customer_id)
- FKs: referenced_table_id (customer_id)
- Booleans: is_active, has_subscription
- Timestamps: created_at, updated_at
Key Constraints
- PRIMARY KEY: unique identifier
- FOREIGN KEY: referential integrity
- UNIQUE: no duplicate values
- NOT NULL: required fields
- CHECK: validate value ranges