Trong quá trình xử lý SQL, sau khi Hive phân tích cú pháp và xây dựng ASTNode, hệ thống sẽ kích hoạt phương thức BaseSemanticAnalyzer.analyze. Đây là bước cốt lõi để chuyển hóa ASTNode thành hệ thống tác vụ (task), qua nhiều giai đoạn tối ưu hóa.
Dưới đây là ví dụ về truy vấn SQL được tối ưu ở các bước khác nhau:
SELECT *
FROM (
SELECT Sname, Sex, Sage, Sdept, COUNT(1) AS num
FROM student_ext
GROUP BY Sname, Sex, Sage, Sdept
) t1
LEFT JOIN student_ext t2 ON t1.Sname = t2.Sname
WHERE t1.Sage > 10 AND t2.Sdept = 'MA';
Sau khi đi qua các bước tối ưu hóa, kế hoạch thực thi được cải tiến như sau:
HiveFilter(condition=[AND(>($2, 10), =($9, 'MA'))])
HiveJoin(condition=[=($0, $6)], joinType=[left])
HiveAggregate(group=[{0, 1, 2, 3}], agg#0=[count($4)])
HiveProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[1])
HiveProject(sname=[$1], sex=[$2], sage=[$3], sdept=[$4])
HiveTableScan(table=[[default.student_ext]])
HiveProject(sno=[$0], sname=[$1], sex=[$2], sage=[$3], sdept=[$4])
HiveTableScan(table=[[default.student_ext]])
So với kế hoạch ban đầu, các bước tối ưu hóa đã loại bỏ các phép chiếu không cần thiết và thu hẹp tập dữ liệu đầu vào cho phép join — giảm đáng kể lượng dữ liệu shuffle.
1. Tạo Kế Hoạch Logic với Calcite (RelNode)
Quá trình tối ưu hóa bắt đầu từ phương thức trừu tượng:
public abstract void analyzeInternal(ASTNode ast) throws SemanticException;
Khi Hive sử dụng Calcite làm trình tối ưu cốt lõi, ASTNode sẽ được chuyển thành đối tượng QB (Query Block), sau đó thành RelNode — biểu diễn logic của truy vấn tương thích với Calcite. Sau khi tối ưu, hệ thống sẽ chuyển ngược RelNode thành Operator Tree.
Tại bước này, gọi đến lớp CalcitePlanner.analyzeInternal.CLUDING việc kiểm tra xem có cần tối ưu hóa dựa trên chi phí (CBO) hay không.
Operator sinkOp = genOPTree(ast, plannerCtx);
Nếu không sử dụng CBO, genOPTree sẽ gọi phương thức cha để tạo.Operator Tree mà không qua Calcite.
Ngược lại, khi CBO được bật, sẽ thu được AST đã tối ưu bằng cách gọi:
ASTNode newAST = getOptimizedAST();
Quá trình này bao gồm nhiều bước:
- Tổng hợp lại các phép tính toán (constant folding)
- Loại bỏ các giá trị null không mong muốn
- Thao tác với join order (sử dụng HepPlanner & MST)
- Tối ưu theo nguyên tắc chi phí (CBO) hoặc mẫu có sẵn (RBO)
2. Các kỹ thuật tối ưu hóa quan trọng
2.1 Tối ưu hóa hàm tổng hợp DISTINCT
Phương thức applyPreJoinOrderingTransforms áp dụng luật HiveExpandDistinctAggregatesRule khi công cụ tính toán hỗ trợ (ví dụ: Tez).
Ví dụ: Chuyển đổi:
SELECT COUNT(DISTINCT colA) FROM table1;
Thành:
SELECT COUNT(1) FROM (SELECT colA FROM table1 GROUP BY colA) alias;
Về bản chất, thay vì lưu toàn bộ giá trị phân biệt vào bộ nhớ (cost mạnh với dữ liệu lớn), ta dùng GROUP BY để xử lý với chi phí bộ nhớ thấp hơn.
2.2 Pushdown Semi-Join
Các luật áp dụng:
- SemiJoinJoinTransposeRule
- SemiJoinFilterTransposeRule
- SemiJoinProjectTransposeRule
Semi-join giúp giảm kết quả dư thừa trong JOIN thông thường. Ví dụ: Thay vì:
SELECT country.* FROM country JOIN city ON country.code = city.country_code WHERE city.population > 20000000;
Dùng:
SELECT country.* FROM country SEMI JOIN city ON country.code = city.country_code WHERE city.population > 20000000;
Sau khi pushdown, các过滤 điều kiện được đưa lên trước, giảm lượng dữ liệu tham gia join.
2.3 Thêm điều kiện NOT NULL cho trường join
Ruật HiveJoinAddNotNullRule thêm điều kiện IS NOT NULL cho các trường trong điều kiện join — do Hive không xử lý NULL = NULL.
Trước:
HiveJoin(condition=[=($0, $6)])
Sau:
HiveFilter(condition=[isnotnull($0)])
HiveFilter(condition=[isnotnull($1)])
Điều này tránh sai lệch kết quả do NULL bị bỏ qua trong so sánh.
2.4 Tối ưu hóa lọc và tính toán trước
Các luật áp dụng đồng thời:
- ReduceExpressionsRule.PROJECT_INSTANCE (rút gọn hằng số như 1+2 = 3)
- ReduceExpressionsRule.FILTER/JOIN_INSTANCE
- HivePreFilteringRule
Ví dụ truy vấn:
SELECT 1+2, a.name, b.money FROM a LEFT JOIN b ON a.id = b.id
WHERE a.name = 'Tran' AND b.dept = 'IT';
Sau tối ưu:
- Giá trị 1+2 được tính sẵn
- Các điều kiện lọc được đẩy xuống tận mức năng table scan, giảm tải cho join.
Kết luận: Việc tích hợp Apache Calcite giúp Hive linh hoạt hỗ trợ cả RBO (Rule-Based Optimization) và CBO (Cost-Based Optimization), từ đó cải thiện hiệu năng truy vấn ở mức độ sâu và chi tiết — không chỉ giới hạn ở preset patterns, mà còn tận dụng một hệ thống luật mở rộng, dễ cấu hình.