CodeGym /Các khóa học /SQL SELF /Tối ưu hóa function để làm việc với dữ liệu lớn

Tối ưu hóa function để làm việc với dữ liệu lớn

SQL SELF
Mức độ, Bài học
Có sẵn

Khi nói về tối ưu function trong PostgreSQL, tụi mình thường nhắc đến hai thứ chính: index và partitioning. Hai kỹ thuật này giúp xử lý dữ liệu lớn nhanh hơn, giảm tính toán thừa và truy cập dữ liệu “chuẩn chỉ”. Giờ cùng đào sâu nhé.

Index trong thế giới database hoạt động giống như mục lục trong sách. Khi tìm thông tin trong sách, bạn đâu có đọc từng trang, mà mở mục lục, tìm chủ đề rồi nhảy thẳng tới trang cần. Index trong PostgreSQL cũng vậy luôn.

Tạo index

Index được tạo bằng lệnh CREATE INDEX. Ví dụ đơn giản nè:

-- Tạo index trên cột id của bảng users để tăng tốc tìm kiếm
CREATE INDEX idx_users_id ON users (id);

Giờ nếu bạn chạy query kiểu:

SELECT * FROM users WHERE id = 42;

PostgreSQL sẽ dùng index vừa tạo để tìm dòng cần cực nhanh.

Ví dụ: Tối ưu function dùng index

Giả sử tụi mình có function lấy dữ liệu đơn hàng từ bảng orders theo user:

CREATE OR REPLACE FUNCTION get_user_orders(user_id INT)
RETURNS TABLE(order_id INT, order_date DATE) AS $$
BEGIN
    RETURN QUERY 
    SELECT id, order_date 
    FROM orders 
    WHERE user_id = user_id;
END; 
$$ LANGUAGE plpgsql;

Nếu bảng orders có hàng triệu dòng, chạy function này sẽ chậm. Giải pháp? Tạo index trên user_id:

CREATE INDEX idx_orders_user_id ON orders (user_id);

Giờ query trong function sẽ nhanh hơn nhiều vì PostgreSQL dùng index để tìm dòng.

Các loại index

PostgreSQL hỗ trợ nhiều loại index, nhưng phổ biến nhất là B-TREE và GIN. So sánh nhanh nè:

Loại index Cách dùng Ví dụ
B-TREE Index chuẩn để tìm kiếm. Tìm theo số, chuỗi (=, >, <).
GIN Cho full-text search hoặc làm việc với JSON. Tìm theo array, JSONB.

Nếu muốn tìm hiểu sâu hơn về index, ghé tài liệu chính thức của PostgreSQL nhé.

Partitioning dữ liệu

Nếu index là tăng tốc tìm kiếm, thì partitioning là cách chia bảng thành các “miếng nhỏ” (partition). Cực kỳ hữu ích khi bạn có lượng dữ liệu khổng lồ trong một bảng.

Ví dụ bạn có bảng orders lưu đơn hàng 10 năm qua. Nếu query tìm đơn hàng tháng trước, PostgreSQL vẫn phải quét cả bảng, rất tốn tài nguyên. Partitioning giải quyết bằng cách chia dữ liệu theo năm chẳng hạn.

Tạo bảng partition

Tạo bảng partition như này nè:

-- Tạo bảng orders làm partition cha
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    order_date DATE NOT NULL,
    user_id INT NOT NULL
) PARTITION BY RANGE (order_date);

-- Tạo bảng con cho từng năm
CREATE TABLE orders_2023 PARTITION OF orders FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
CREATE TABLE orders_2022 PARTITION OF orders FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');

Giờ nếu bạn chạy query kiểu:

SELECT * FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2023-02-01';

PostgreSQL sẽ biết ngay chỉ cần tìm trong bảng orders_2023, khỏi phải quét cả bảng lớn.

Dùng partitioning trong function

Giả sử tụi mình có function lấy đơn hàng theo năm. Nhờ partitioning, query trong function sẽ nhanh hơn vì PostgreSQL chỉ làm việc với bảng con cụ thể.

CREATE OR REPLACE FUNCTION get_orders_by_year(year INT)
RETURNS TABLE(order_id INT, order_date DATE) AS $$
BEGIN
    RETURN QUERY 
    SELECT id, order_date 
    FROM orders 
    WHERE order_date >= make_date(year, 1, 1) 
      AND order_date < make_date(year + 1, 1, 1);
END;
$$ LANGUAGE plpgsql;

Case thực tế

  1. Case về index

Tìm theo chuỗi: nếu bạn có bảng sản phẩm và hay tìm theo tên, tạo index trên trường name nhé:

CREATE INDEX idx_products_name ON products (name);

Tăng tốc sắp xếp: nếu query hay sort theo ngày, tạo index luôn:

CREATE INDEX idx_orders_date ON orders (order_date);
  1. Case về partitioning

Dữ liệu lịch sử: nếu bảng có dữ liệu theo thời gian, partition theo ngày, tháng hoặc năm sẽ tăng tốc query đáng kể.

Dữ liệu địa lý: nếu bảng có dữ liệu theo quốc gia, tạo partition cho từng nước luôn.

Lỗi thường gặp và cách xử lý

Nhiều dev mắc lỗi tạo quá nhiều index. Việc này làm chậm insert/update vì PostgreSQL phải update index mỗi lần bảng thay đổi. Lời khuyên: chỉ tạo index trên trường bạn hay dùng trong điều kiện hoặc sort thôi.

Một lỗi nữa là partitioning sai cách. Nếu tạo quá nhiều partition nhỏ (ví dụ chia theo ngày thay vì tháng), sẽ tốn công quản lý bảng con.

2
Nhiệm vụ
SQL SELF, mức độ, bài học
Đã khóa
Tạo chỉ mục để tăng tốc tìm kiếm
Tạo chỉ mục để tăng tốc tìm kiếm
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION