Hãy tưởng tượng bạn cần tải một triệu dòng dữ liệu. Nếu làm chậm, server của bạn sẽ bị chiếm dụng lâu, người dùng có thể thấy database chạy chậm, mà tệ hơn nữa — cà phê của bạn sẽ nguội trước khi xong việc. Tối ưu hóa giúp tránh quá tải server, giảm thời gian chờ và giảm khả năng lỗi khi tải dữ liệu.
Bắt đầu với các bước đơn giản, rồi chuyển sang các chiêu trò nâng cao hơn nhé.
Tắt index và trigger
Index và trigger là những thứ tuyệt vời giúp database của chúng ta thông minh và phản hồi nhanh. Nhưng khi tải dữ liệu hàng loạt, chúng có thể làm chậm quá trình rất nhiều, vì server sẽ cố update index và chạy trigger cho từng dòng bạn tải vào.
Để tạm thời giải phóng hệ thống khỏi gánh nặng này, bạn có thể tắt chúng đi.
Ví dụ tắt index và trigger:
-- Tắt trigger cho bảng
ALTER TABLE students DISABLE TRIGGER ALL;
-- Tải dữ liệu
COPY students FROM '/path/to/students.csv' DELIMITER ',' CSV HEADER;
-- Bật lại trigger
ALTER TABLE students ENABLE TRIGGER ALL;
Nó hoạt động như thế nào?
- Chúng ta tạm thời tắt tất cả trigger bằng lệnh
DISABLE TRIGGER ALL. - Sau khi tải dữ liệu xong thì bật lại trigger bằng
ENABLE TRIGGER ALL.
Lỗi thường gặp: nếu bạn quên bật lại trigger, một số quy trình tự động (ví dụ cập nhật trường mặc định) có thể chạy sai. Đừng quên bật lại mọi thứ — giống như thoát khỏi chế độ "máy bay" trên điện thoại ấy.
Dùng transaction
Transaction cho phép bạn tải tất cả dữ liệu như một thao tác lớn duy nhất. Nếu có gì sai, bạn có thể rollback, và database của bạn sẽ không thành nồi cháo dữ liệu lỗi.
Ví dụ dùng transaction:
-- Bắt đầu transaction
BEGIN;
-- Tải dữ liệu
COPY courses FROM '/path/to/courses.csv' DELIMITER ',' CSV HEADER;
-- Xác nhận thay đổi
COMMIT;
Tại sao lại nhanh hơn?
Khi bạn tải dữ liệu không dùng transaction, server xác nhận thay đổi sau mỗi dòng. Dùng transaction, server chỉ xác nhận một lần ở cuối, tiết kiệm rất nhiều thời gian.
Tắt kiểm tra toàn vẹn dữ liệu
Nếu bạn không cần kiểm tra khóa ngoại hoặc ràng buộc unique khi tải, hãy tắt chúng đi. Nếu không, database sẽ kiểm tra từng dòng, làm chậm quá trình.
Ví dụ tắt kiểm tra toàn vẹn:
SET session_replication_role = 'replica';
-- Tải dữ liệu
COPY enrollments FROM '/path/to/enrollments.csv' DELIMITER ',' CSV HEADER;
SET session_replication_role = 'origin';
session_replication_role = 'replica' sẽ tắt kiểm tra toàn vẹn dữ liệu (ví dụ unique và ràng buộc FOREIGN KEY).
Tăng bộ nhớ cho thao tác
Cấu hình bộ nhớ PostgreSQL có thể cải thiện hiệu suất tải dữ liệu. Các tham số chính là work_mem và maintenance_work_mem.
Ví dụ tăng bộ nhớ:
-- Tăng bộ nhớ
SET work_mem = '64MB';
SET maintenance_work_mem = '256MB';
-- Tải dữ liệu
COPY teachers FROM '/path/to/teachers.csv' DELIMITER ',' CSV HEADER;
Nó giúp gì?
work_memdùng cho các thao tác trung gian như sort hoặc hash.maintenance_work_memảnh hưởng đến các thao tác liên quan đến index, ví dụ rebuild index.
Mẹo: Cẩn thận khi tăng bộ nhớ, nhất là trên hệ thống có tài nguyên hạn chế.
Chuẩn bị dữ liệu trước khi tải
Chuẩn bị dữ liệu có thể giảm đáng kể thời gian tải. Ví dụ, nếu bạn có dòng trùng lặp, hãy lọc trước để PostgreSQL không phải xử lý dữ liệu thừa.
Ví dụ làm sạch dữ liệu:
Nếu bạn có file với dòng trùng, có thể dùng Python để loại bỏ.
import pandas as pd
# Tải file CSV
data = pd.read_csv('students.csv')
# Xóa dòng trùng
data = data.drop_duplicates()
# Lưu file CSV sạch
data.to_csv('students_clean.csv', index=False)
Phân vùng dữ liệu
Nếu bạn có file cực lớn, hãy chia nhỏ thành nhiều file nhỏ hơn. PostgreSQL sẽ xử lý hiệu quả hơn.
Ví dụ:
Chia file large_data.csv thành các phần 1000 dòng bằng Linux:
split -l 1000 large_data.csv chunk_
Sau đó tải từng phần một:
COPY students FROM 'chunk_aa' DELIMITER ',' CSV HEADER;
COPY students FROM 'chunk_ab' DELIMITER ',' CSV HEADER;
-- Và tiếp tục
Tải dữ liệu ở chế độ nền
Nếu có thể, hãy dùng process nền để tải dữ liệu, tránh làm nặng database chính.
Các công cụ như pg_cron giúp chạy job theo lịch.
Ví dụ: cấu hình tải nền với pg_cron:
CREATE EXTENSION pg_cron;
SELECT cron.schedule('*/5 * * * *', $$COPY students FROM '/path/to/data.csv' DELIMITER ',' CSV HEADER$$);
Cứ mỗi 5 phút, dữ liệu từ file sẽ được tải vào bảng.
Đây chỉ là ví dụ, thực tế không nên làm vậy nhé! Mình chỉ muốn cho bạn thấy PostgreSQL rất linh hoạt, bạn có thể cực kỳ chủ động thêm dữ liệu ngay từ SQL script.
Bẫy thường gặp
Một số điều cần chú ý:
- Nếu bạn tắt index và trigger, nhớ bật lại nhé! Quên là sau phải đi sửa lỗi đấy.
- Khi tăng tham số bộ nhớ, để ý tài nguyên server: một truy vấn "háu ăn" có thể ngốn sạch RAM.
- Dùng transaction thì hãy chắc file dữ liệu không có lỗi nghiêm trọng. Một lỗi thôi là rollback toàn bộ.
Gợi ý cho tương lai
Giờ bạn đã biết cách tối ưu hóa việc tải dữ liệu hàng loạt — từ tắt index đến dùng transaction. Kỹ năng này giúp bạn không chỉ tải nhanh hơn mà còn tiết kiệm tài nguyên server, giữ bình tĩnh, cà phê và làm người dùng hài lòng.
Lần sau nếu phải làm việc với file cỡ gigabyte, bạn sẽ sẵn sàng rồi đó!
GO TO FULL VERSION