7 điểm bởi GN⁺ 2024-05-01 | 1 bình luận | Chia sẻ qua WhatsApp

Cách hoạt động phổ biến của các engine cơ sở dữ liệu SQL

  • Mọi engine cơ sở dữ liệu SQL đều hoạt động theo cách tương tự
    • Chuyển câu lệnh SQL đầu vào thành "prepared statement"
    • "Thực thi" prepared statement để tạo ra kết quả
  • Trong SQLite, prepared statement được biểu diễn bằng một instance của đối tượng sqlite3_stmt
  • Có hai cách lớn để biểu diễn prepared statement
    • Cách dùng bytecode: được SQLite sử dụng
    • Cách dùng cây đối tượng: được MySQL, PostgreSQL sử dụng

Ưu điểm của cách dùng bytecode

  • Dễ hiểu
    • Được cấu thành từ một danh sách các lệnh đơn giản nên dễ in ra
    • Có thể dùng từ khóa EXPLAIN để xem bytecode của câu lệnh SQL
  • Dễ gỡ lỗi
    • Phân tách rõ ràng giữa giai đoạn parsing/phân tích và giai đoạn thực thi
    • Trong bản dựng debug, có thể theo dõi việc thực thi bytecode bằng lệnh PRAGMA vdbe_trace=ON
  • Có thể thực thi theo kiểu tăng dần
    • Câu lệnh SQL được viết dưới dạng bytecode có thể chạy từng hàng, dừng lại rồi tiếp tục lại
    • Cách dùng cây đối tượng thực thi toàn bộ cây trong một lần nên khó thực thi tăng dần
  • Mức sử dụng bộ nhớ thấp
    • Bytecode có kích thước nhỏ hơn AST
    • Prepared statement thường được cache lâu trong bộ nhớ nên mức dùng bộ nhớ là yếu tố quan trọng
  • Tốc độ thực thi nhanh
    • Có ít quyết định phải đưa ra hơn ở mỗi bước nên thực thi nhanh hơn

Ưu điểm của cách dùng cây đối tượng

  • Có thể chỉnh sửa kế hoạch truy vấn tại runtime
    • Cây đối tượng dễ sửa đổi ngay cả trong lúc thực thi
    • Có thể tối ưu hóa động theo tiến độ của truy vấn
  • Dễ song song hóa
    • Có thể gán từng nút xử lý cho một thread riêng
    • Chỉ cần đồng bộ việc truyền dữ liệu giữa các nút
    • Có lợi khi chạy các truy vấn phân tích dữ liệu lớn (OLAP) trên nhiều lõi

Ý kiến của GN⁺

  • Mục tiêu chính của SQLite là xử lý giao dịch (OLTP) trong môi trường Internet vạn vật, nên cách dùng bytecode có vẻ phù hợp. Vì nó đơn giản, nhẹ nhưng vẫn có thể mang lại hiệu năng nhanh.
  • Trong khi đó, MySQL hay PostgreSQL cũng được dùng nhiều cho phân tích dữ liệu quy mô lớn, nên ưu điểm của cách dùng cây đối tượng — có thể tối ưu động kế hoạch thực thi truy vấn và song song hóa — có thể nổi bật hơn.
  • Tuy vậy, cách dùng cây đối tượng cũng có nhược điểm là khó gỡ lỗi hoặc phân tích hiệu năng. Ngoài ra, do chi phí duyệt cây, trong các truy vấn đơn giản nó thậm chí có thể chậm hơn bytecode.
  • Điều quan trọng là chọn cách tiếp cận phù hợp với mục đích và trường hợp sử dụng. Với RDBMS đa dụng, cũng đáng cân nhắc một cách tiếp cận lai dung hòa ưu và nhược điểm của cả hai.

1 bình luận

 
GN⁺ 2024-05-01
Ý kiến trên Hacker News
  • Việc SQLite dùng máy ảo bytecode (VM) thay vì cây cú pháp trừu tượng (AST) để thực thi truy vấn SQL là một lựa chọn thiết kế thú vị đối với cơ sở dữ liệu. Những ưu điểm của bytecode so với AST gồm:

    • Gọn nhẹ: Bytecode gọn hơn AST vì không cần malloc ẩn/tiêu đề đối tượng và con trỏ cho các biểu thức con.
    • Hiệu năng: Thực thi bytecode nhanh hơn nhờ tận dụng cache tốt hơn và ít cache miss do lần theo con trỏ.
    • Thực thi tăng dần: Với ngăn xếp tường minh, việc tạm dừng và tiếp tục thực thi mà không phải tháo ngăn xếp cơ sở sẽ dễ hơn khi dùng bytecode.
  • VM bytecode và trình thông dịch thường gắn với các ngôn ngữ lập trình đa dụng, nhưng chúng cũng có thể hữu ích một cách đáng ngạc nhiên trong các bối cảnh khác như:

    • eBPF: Cơ chế mở rộng của nhân Linux.
    • Ngôn ngữ biểu thức DWARF: Được dùng trong các trình gỡ lỗi như GDB, LLDB.
    • Định dạng tệp RAR: Bao gồm mã hóa bytecode cho các phép biến đổi dữ liệu tùy chỉnh.
  • Microsoft SQL Server nội bộ sử dụng cây đối tượng, nhưng đầu ra query plan vẫn ở dạng bảng, cho thấy việc biểu diễn cây đối tượng thành bảng là không hề dễ.

  • Lập trình viên thường biết chính xác tra cứu chỉ mục nào cần diễn ra trong một vòng lặp, nên trong một số trường hợp, viết bytecode trực tiếp hoặc dùng một ngôn ngữ mệnh lệnh cấp cao có thể có lợi hơn SQL. Việc biểu đạt điều này bằng SQL có thể trở thành gánh nặng.

  • Nếu nút thắt cổ chai không nằm ở việc thực thi bytecode (ví dụ: tốc độ bộ nhớ hoặc đĩa), thì việc chuyển sang mã máy native thông qua biên dịch JIT có thể không thực sự cần thiết.

  • Nhiều ngôn ngữ lập trình như Python, Ruby, Lua nội bộ dùng bytecode hoặc AST. Do các quyết định thiết kế của cơ sở dữ liệu, những câu lệnh dễ phân tích cú pháp có thể hữu ích cho các thư viện bên thứ ba hoặc các triển khai ORM vốn dễ phát sinh lỗi.