0

Trino SQL Bài học 39: Đọc hiểu và phân tích kế hoạch thực thi (EXPLAIN)

Mục tiêu bài học:

  • Hiểu bản chất định tuyến của Trino: SQL là ngôn ngữ khai báo (Declarative), Engine mới là người quyết định cách thực thi (Imperative).

  • Sử dụng EXPLAIN để xem Kế hoạch logic (Logical Plan).

  • Sử dụng EXPLAIN (TYPE DISTRIBUTED) để hiểu cách Trino chia nhỏ công việc cho các Worker.

  • Dùng EXPLAIN ANALYZE để "khám nghiệm tử thi" một truy vấn chậm và tìm ra thắt cổ chai (Bottleneck).

1. Tại sao cùng một câu lệnh, lúc chạy nhanh lúc chạy chậm?

Khi bạn viết SQL, bạn đang nói cho Trino biết "Bạn muốn kết quả gì" (What), chứ không phải "Làm như thế nào" (How).

Trino có một bộ não gọi là Cost-Based Optimizer (CBO). Khi nhận câu lệnh của bạn, CBO sẽ phân tích siêu dữ liệu (thống kê số dòng, dung lượng bảng) và vạch ra hàng chục lộ trình khả thi. Cuối cùng, nó chọn ra lộ trình (Query Plan) tốn ít CPU và RAM nhất để chạy. Đôi khi CBO đoán sai, hoặc do bạn viết SQL chưa chuẩn (như lạm dụng Correlated Subquery ở Bài 37), dẫn đến Trino chọn một lộ trình thảm họa. EXPLAIN là công cụ để bạn nhìn thấu bộ não này.

2. EXPLAIN: Xem kế hoạch Logic (Logical Plan)

Bằng cách đặt chữ EXPLAIN trước bất kỳ câu SELECT nào, Trino sẽ không chạy câu lệnh đó, mà chỉ in ra bản vẽ thiết kế (Blueprint) của nó.

SQL

EXPLAIN 
SELECT c.mktsegment, SUM(o.totalprice)
FROM tpch.tiny.customer AS c
JOIN tpch.tiny.orders AS o ON c.custkey = o.custkey
GROUP BY c.mktsegment;

Cách đọc Kế hoạch Logic: Trino in ra một cái cây (Tree). Bạn phải đọc từ dưới cùng lên trên cùng (Bottom-up).

  1. TableScan: Ở dưới đáy, Trino sẽ quét bảng (quét bảng orders và bảng customer).

  2. Filter/Project: Lọc dữ liệu và chọn các cột cần thiết.

  3. InnerJoin: Trino quyết định thuật toán Join (ví dụ: Hash Join hay Nested Loop).

  4. Aggregate: Gom nhóm và tính toán (SUM, GROUP BY).

  5. Output: Trả kết quả về màn hình.

3. EXPLAIN (TYPE DISTRIBUTED): Bản đồ tác chiến phân tán

Kế hoạch logic chỉ là lý thuyết. Trên thực tế, Trino là hệ thống phân tán với hàng chục Worker Node. Kế hoạch logic sẽ được chặt ra thành nhiều Fragments (Mảnh vỡ/Giai đoạn).

SQL

EXPLAIN (TYPE DISTRIBUTED) 
SELECT ...

Các khái niệm cốt lõi trong Distributed Plan:

  • Fragment: Mỗi Fragment là một nhiệm vụ độc lập được giao cho một nhóm Worker chạy song song.

  • Exchange (Trao đổi dữ liệu): Khi Fragment 1 làm xong, nó phải ném dữ liệu cho Fragment 2. Quá trình bay qua lại trên mạng Network này gọi là Exchange.

    • Local Exchange: Dữ liệu trao đổi ngay trong RAM của cùng một máy (Rất nhanh).

    • Remote Exchange: Máy Worker A phải gửi dữ liệu qua cáp mạng cho máy Worker B (Rất chậm, tốn I/O).

Góc nhìn Kỹ sư: Một Query Plan tốt là một Plan hạn chế tối đa các Remote Exchange khổng lồ.

4. EXPLAIN ANALYZE: "Khám nghiệm tử thi" truy vấn thực tế

EXPLAIN chỉ là sự phỏng đoán của Trino trước khi chạy. Đôi khi Trino đoán bảng này chỉ có 1000 dòng, nhưng thực tế nó có 1 tỷ dòng.

Để biết chính xác chuyện gì đã xảy ra, bạn dùng EXPLAIN ANALYZE. Lưu ý: Lệnh này sẽ thực sự chạy câu truy vấn của bạn đến khi hoàn tất, sau đó nó mới nhả ra báo cáo chi tiết về CPU, Memory và thời gian của từng Node.

SQL

EXPLAIN ANALYZE 
SELECT ...

Những chỉ số vàng cần chú ý trong kết quả:

  • CPU time: Node nào tiêu tốn nhiều thời gian CPU nhất? (Thường là các node Aggregate có GROUP BY quá nhiều cột, hoặc dùng CROSS JOIN).

  • Scheduled time: Thời gian thực tế chờ đợi.

  • Input rows: Số dòng dữ liệu bơm vào. Nếu bạn thấy Input là 1 tỷ dòng, nhưng Output chỉ có 10 dòng, nghĩa là bạn đã quên lọc WHERE từ sớm, bắt hệ thống phải tính toán rác.

  • Data Skew (Lệch dữ liệu): Trong EXPLAIN ANALYZE, Trino sẽ hiển thị sự phân phối dữ liệu. Nếu bạn thấy một Worker xử lý 99% dữ liệu, các Worker khác ngồi chơi rảnh rỗi (0%), đó là hiện tượng Data Skew. Cách giải quyết là cấu hình lại thuật toán Hashing hoặc phân mảnh lại Partition.

5. Dấu hiệu nhận biết "Báo động đỏ" trong Query Plan

Khi đọc EXPLAIN, nếu bạn thấy các từ khóa sau, hãy cẩn thận và tìm cách viết lại SQL:

  1. NestedLoopJoin: Như đã đề cập ở Bài 24, đây là thảm họa. Trino đang quét từng dòng chéo nhau do bạn dùng Non-Equi JOIN mà thiếu mỏ neo =.

  2. CrossJoinNode: Dữ liệu bị bùng nổ (Cartesian Product - Bài 23).

  3. TableScan (Full) trên bảng khổng lồ: Trino đang quét toàn bộ dữ liệu lịch sử thay vì chỉ quét ngày hiện tại do bạn thiếu điều kiện giới hạn Partition (như WHERE ds = '2023-10-10').


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí