📖 Thiết kế Cơ sở dữ liệu - Indexes và Query Optimization
70 phút

Indexes và Query Optimization

Giới thiệu Indexes

Indexes giúp cải thiện performance của queries bằng cách cung cấp cấu trúc dữ liệu để tìm kiếm nhanh.

Types of Indexes

B-Tree Index (Mặc định)

-- Single column index
CREATE INDEX idx_customer_email ON customers(email);

-- Composite index
CREATE INDEX idx_orders_date_customer ON orders(order_date, customer_id);

-- Unique index
CREATE UNIQUE INDEX idx_unique_product_sku ON products(sku);

Partial Index

-- Chỉ index các bản ghi active
CREATE INDEX idx_active_products ON products(name) 
WHERE is_active = true;

Expression Index

-- Index trên kết quả của expression
CREATE INDEX idx_lower_product_name ON products(LOWER(name));

Query Execution Plans

EXPLAIN Command

EXPLAIN SELECT * FROM orders WHERE customer_id = 123;

EXPLAIN ANALYZE

EXPLAIN ANALYZE 
SELECT * FROM orders 
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';

Query Optimization Techniques

Sargable Queries

-- KHÔNG Sargable (không sử dụng index)
SELECT * FROM products WHERE YEAR(created_date) = 2024;

-- Sargable (sử dụng index)
SELECT * FROM products 
WHERE created_date BETWEEN '2024-01-01' AND '2024-12-31';

Avoid SELECT *

-- KHÔNG TỐT
SELECT * FROM customers WHERE city = 'Hanoi';

-- TỐT HƠN
SELECT customer_id, name, email 
FROM customers 
WHERE city = 'Hanoi';

JOIN Optimization

-- Sử dụng EXISTS thay vì IN cho subqueries lớn
SELECT c.* 
FROM customers c
WHERE EXISTS (
  SELECT 1 FROM orders o 
  WHERE o.customer_id = c.customer_id 
  AND o.total_amount > 1000
);

Index Strategy

Khi nào nên tạo Index

  • Columns trong WHERE clause
  • Columns trong JOIN conditions
  • Columns trong ORDER BY
  • Foreign keys

Khi nào KHÔNG nên tạo Index

  • Tables nhỏ
  • Columns thường xuyên được update
  • Columns có cardinality thấp (ít giá trị unique)

Monitoring Index Usage

-- PostgreSQL: xem index usage
SELECT * FROM pg_stat_user_indexes;

-- MySQL: xem index usage
SHOW INDEX FROM table_name;

Common Performance Issues

N+1 Query Problem

-- VẤN ĐỀ: Một query lấy danh sách + N queries lấy chi tiết
SELECT * FROM orders WHERE customer_id = 123; -- 1 query
-- Sau đó với mỗi order: 
SELECT * FROM order_items WHERE order_id = ?; -- N queries

-- GIẢI PHÁP: Sử dụng JOIN hoặc batch query
SELECT o.*, oi.*
FROM orders o
LEFT JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.customer_id = 123;

Missing Indexes

-- Query chậm do thiếu index
SELECT * FROM orders 
WHERE status = 'shipped' 
AND order_date >= '2024-01-01';

-- Tạo composite index
CREATE INDEX idx_orders_status_date 
ON orders(status, order_date);

📝 Bài tập (1)

  1. Phân tích query execution plans và đề xuất tối ưu

Bài học "Indexes và Query Optimization" - Khóa học "Thiết kế Cơ sở dữ liệu"