DuckDB: SQLite cho Analytics – Bí kíp xử lý hàng chục GB dữ liệu mượt mà trên Laptop

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Câu chuyện RAM và những file CSV “khổng lồ”

Vừa rồi mình xử lý tập dữ liệu log người dùng khoảng 20 triệu dòng, file CSV nặng tầm 5GB. Theo thói quen, mình bật ngay Jupyter Notebook và gõ import pandas as pd. Chỉ sau vài giây, thanh RAM 16GB trên con laptop báo động đỏ ở mức 95%. Máy bắt đầu đứng hình, và kết quả là dòng lỗi MemoryError xuất hiện sau 2 phút chờ đợi vô vọng.

Kịch bản này chắc chắn không lạ lẫm với dân làm dữ liệu. Khi file quá lớn để Excel mở nổi và cũng quá nặng để Pandas nạp hết vào bộ nhớ, chúng ta thường nghĩ đến việc dựng server Database như PostgreSQL. Tuy nhiên, việc cài đặt một hệ quản trị cồng kềnh, cấu hình port hay user chỉ để phân tích một file offline là điều rất lãng phí thời gian.

Tại sao các công cụ quen thuộc lại “hụt hơi”?

Để tìm giải pháp đúng, trước tiên cần hiểu rõ giới hạn của các công cụ cũ. Qua quá trình làm việc với MySQL, PostgreSQL hay MongoDB, mình nhận thấy 3 rào cản chính:

  • Pandas ngốn RAM quá mức: Thư viện này nạp toàn bộ dữ liệu vào RAM dưới dạng object Python. Một file CSV 1GB khi vào tay Pandas có thể chiếm tới 4-5GB RAM do cách lưu trữ chưa tối ưu.
  • Hệ quản trị OLTP lưu trữ theo dòng: Nếu bạn chỉ cần tính tổng doanh thu của một cột, các DB như MySQL vẫn phải đọc toàn bộ dòng dữ liệu từ ổ cứng. Đây là “thắt nút cổ chai” I/O cực lớn.
  • SQLite không dành cho tính toán: Dù là database nhúng tuyệt vời, SQLite vẫn lưu trữ theo dòng và không được tối ưu cho các tác vụ aggregation (tính tổng, trung bình) trên hàng triệu bản ghi.

Ba hướng giải quyết phổ biến (và nhược điểm)

Với đống dữ liệu khoảng vài chục GB, anh em thường cân nhắc các lựa chọn sau:

  1. Nâng cấp RAM: Phương án này tốn kém và chỉ là giải pháp tình thế. Khi dữ liệu vọt lên 100GB, không máy cá nhân nào chịu thấu.
  2. Sử dụng Dask hoặc Polars: Các thư viện này xử lý song song rất tốt. Tuy nhiên, cú pháp mới lạ đôi khi khiến workflow của bạn bị chậm lại do phải học lại từ đầu.
  3. Triển khai Database OLAP chuyên dụng: ClickHouse hay Druid cho hiệu năng cực khủng. Ngược lại, việc vận hành chúng cho nhu cầu cá nhân là bài toán “dùng dao mổ trâu giết gà”.

DuckDB: Giải pháp “cứu cánh” cho phân tích dữ liệu cục bộ

DuckDB chính là lựa chọn cân bằng nhất hiện nay. Được mệnh danh là “SQLite for Analytics”, nó hoạt động theo dạng cột (column-oriented) và chạy trực tiếp bên trong tiến trình Python. Bạn không cần server, không cần cấu hình phức tạp nhưng vẫn có sức mạnh của một kho dữ liệu chuyên nghiệp.

1. Cài đặt trong một nốt nhạc

Việc thiết lập DuckDB cực kỳ nhẹ nhàng. Bạn không cần Docker hay các dịch vụ nền, chỉ một dòng lệnh duy nhất là đủ khởi đầu.

pip install duckdb

2. Query trực tiếp trên file: Không đợi chờ, không tốn RAM

Tính năng giá trị nhất của DuckDB là khả năng truy vấn thẳng vào file mà không cần import. Nhờ cơ chế streaming execution, nó chỉ nạp đúng những phần dữ liệu cần thiết để trả về kết quả.

Thử nghiệm tính tổng doanh thu từ file 5GB với vài dòng code:

import duckdb

# Query trực tiếp từ file CSV, kết quả trả về chỉ mất vài giây
result = duckdb.query("""
    SELECT category, SUM(price) as total_revenue
    FROM 'large_data.csv'
    GROUP BY category
    ORDER BY total_revenue DESC
""").df()

print(result)

Trong khi Pandas sẽ báo lỗi, DuckDB xử lý file theo từng khối nhỏ (chunks). Công cụ thực thi vector hóa giúp nó xử lý hàng triệu dòng chỉ trong tích tắc.

3. Phối hợp nhịp nhàng với Pandas và Polars

Thông thường, mình dùng DuckDB để lọc và tính toán thô dữ liệu lớn. Sau khi dữ liệu đã gọn nhẹ, mình mới đẩy sang Pandas để vẽ biểu đồ. DuckDB hỗ trợ đọc trực tiếp từ biến DataFrame trong RAM với chi phí copy dữ liệu bằng không (Zero-copy).

import pandas as pd
import duckdb

# Tận dụng SQL để lọc dữ liệu ngay trên DataFrame
df_raw = pd.read_csv('small_sample.csv')
refined_df = duckdb.query("SELECT * FROM df_raw WHERE price > 100").to_df()

4. Lưu trữ dữ liệu lâu dài

Khi cần lưu lại kết quả trung gian để tái sử dụng, DuckDB cho phép ghi vào một file database duy nhất tương tự SQLite.

# Kết nối và lưu trữ bền vững
con = duckdb.connect('analysis_report.db')

# Tạo bảng từ CSV chỉ trong một câu lệnh
con.execute("CREATE TABLE sales AS SELECT * FROM read_csv_auto('sales.csv')")
con.close()

Kinh nghiệm tối ưu từ thực tế

Sau khi áp dụng DuckDB vào nhiều dự án, đây là những lưu ý quan trọng để bạn đạt hiệu suất cao nhất:

  • Chuyển sang định dạng Parquet: Đọc Parquet nhanh hơn CSV gấp 10-20 lần do tối ưu hóa dạng cột. Bạn có thể convert nhanh bằng lệnh: COPY (SELECT * FROM 'data.csv') TO 'data.parquet' (FORMAT PARQUET);
  • Tin dùng read_csv_auto: Hàm này tự động nhận diện kiểu dữ liệu và header chính xác đến 99%, giúp bạn rảnh tay hơn nhiều.
  • Kiểm soát tài nguyên: Trên các server yếu, hãy giới hạn RAM để tránh tranh chấp bộ nhớ với service khác bằng lệnh SET max_memory='2GB';.
  • Ưu tiên SQL: Cùng một logic tính toán, SQL chạy trong DuckDB thường nhanh hơn vòng lặp Python gấp nhiều lần nhờ tối ưu hóa ở tầng thấp.

DuckDB đã thay đổi hoàn toàn cách mình xử lý dữ liệu trên máy cá nhân. Nó xóa tan khoảng cách giữa sự tiện lợi của file cục bộ và sức mạnh của các hệ thống Big Data chuyên nghiệp. Nếu bạn đang mệt mỏi vì phải chờ đợi Pandas, hãy thử chuyển qua DuckDB, tốc độ của nó chắc chắn sẽ khiến bạn bất ngờ.

Share: