Skip to content
All essays
ArchitectureFebruary 11, 202510 min

Database Fundamentals: SQL vs NoSQL Decision Guide

Understand database fundamentals. Learn when to use SQL vs NoSQL, normalization, and database design principles.

Ü
Ümit Uz
Mobile & Full Stack Developer

Relational Databases (SQL)

When to Use SQL

  • Structured data: Fixed schemas, known relationships
  • ACID compliance: Financial transactions, inventory
  • Complex queries: JOINs, aggregations, subqueries
  • Data integrity: Foreign keys, constraints
sql
-- PostgreSQL example
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  created_at TIMESTAMP DEFAULT NOW()
);

SELECT u.*, o.*
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2025-01-01';

NoSQL Databases

When to Use NoSQL

  • Unstructured data: Flexible schemas, rapid iteration
  • High write throughput: Social media feeds, logs
  • Horizontal scaling: Distributed systems
  • Document storage: JSON-like data structures
javascript
// MongoDB example
db.users.insertOne({
  email: 'user@example.com',
  profile: {
    name: 'John',
    preferences: {
      theme: 'dark'
    }
  },
  tags: ['developer', 'javascript']
});

db.users.find({
  'profile.preferences.theme': 'dark'
});

Decision Matrix

| Factor | Choose SQL | Choose NoSQL | |--------|------------|--------------| | Schema flexibility | Fixed schema | Flexible schema | | Query complexity | Complex relationships | Simple queries | | Scaling | Vertical scaling | Horizontal scaling | | Transaction support | ACID required | Eventual consistency OK | | Data structure | Relational | Document/Key-value/Graph |

Database Design Principles

Normalization (SQL)

sql
-- First Normal Form (1NF): Eliminate repeating groups
-- Second Normal Form (2NF): Remove partial dependencies
-- Third Normal Form (3NF): Remove transitive dependencies

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  user_id INTEGER REFERENCES users(id),
  product_id INTEGER REFERENCES products(id),
  quantity INTEGER NOT NULL,
  order_date TIMESTAMP DEFAULT NOW()
);

Denormalization (NoSQL)

javascript
// Embed related data for performance
db.users.insertOne({
  _id: 'user123',
  email: 'user@example.com',
  orders: [
    { product: 'Widget A', quantity: 2, date: '2025-02-10' },
    { product: 'Widget B', quantity: 1, date: '2025-02-11' }
  ]
});

Performance Optimization

Indexing

sql
-- SQL Indexes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);
javascript
// MongoDB Indexes
db.users.createIndex({ email: 1 });
db.orders.createIndex({ user_id: 1, order_date: -1 });

Connection Pooling

javascript
// PostgreSQL connection pool
const { Pool } = require('pg');

const pool = new Pool({
  host: 'localhost',
  database: 'myapp',
  max: 20, // Maximum pool size
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
});

Migration Strategies

SQL to NoSQL

  1. 1Assess schema: Identify relationships
  2. 2Denormalize: Combine related data
  3. 3Map data types: Convert SQL types to NoSQL
  4. 4Migrate data: Use ETL tools
  5. 5Update application: Modify queries

Conclusion

Choose SQL for structured data with relationships. Choose NoSQL for flexible schemas and horizontal scaling. Many applications use both!

Related essays

Next essay
Clean Code: Writing Maintainable Software