Thời gian gần đây, mình phải làm việc với Apache Hive thường xuyên. Việc làm sao để thời gian thực hiện các câu query trên Hive ngắn hơn trở nên rất cần thiết. Dưới đây là tổng hợp một số cách cơ bản để cải thiện performance cho Hive queries.

1. Sử dụng Apache Tez execution engine

Thiết lập mặc định là Hive sẽ sử dụng Map-reduce engine để thực thi các câu query. Thay vào đó, ta có thể sử dụng Tez engine - tốc độ xử lý sẽ nhanh hơn rất nhiều khi ta dùng Map-reduce.

Nếu Tez chưa được setting thành query engine mặc định trên môi trường Hadoop thì ta có thể dùng Tez bằng cách chạy thiết lập sau khi bắt đầu Hive query

set hive.execution.engine=tez;

Và khi đó mọi câu Hive query sẽ được thực thi bằng Tez execution engine.

Ngoài ra, ta cũng có thể thiết lập Tez enginze thành execution engine mặc định cho Hive qua Ambari

Chi tiết về Tez có thể tham khảo tại: Tez Homepage

2. Dùng ORCFile

Lời khuyên từ Hotonwork là Store all data in ORCFile format.

Sau đây là 1 số điểm mạnh của ORCFile

  • Nén dữ liệu hiệu quả

  • Tốc độ đọc nhanh: Với built-in index, min/max values, predicate pushdown, Bloom filters, ... giúp cho tốc độ đọc dữ liệu định dạng ORCFile nhanh

  • Đã được khẳng định trong các hệ thống lớn. Ví dụ: Facebook dùng ORC file format cho hệ thống 300+ PB dữ liệu

Để dùng ORCFile ta chỉ cần thêm STORED AS orc vào cuối create table statements như sau

CREATE TABLE mytable (
...
) STORED AS orc;

Ta cũng có thể đơn giản chuyển data cũ sang dạng ORCFile bằng cách tạo 1 table copy như sau, rồi xóa table cũ đi.

CREATE TABLE a_orc STORED AS ORC AS SELECT * FROM A; 

Bình thường ta có thể sử dụng setting mặc định cho ORCFile. Tuy nhiên một số trường hợp cần thay đổi, ta có thểm tham khảo bảng sau:

Table 1. ORC Properties
Key
Default Setting
Notes
orc.compress  ZLIB Các kiểu nén (NONE, ZLIB, SNAPPY).
orc.compress.size 262,144
Số bytes trên mỗi block nén
orc.stripe.size 268,435,456
Số bytes trên mỗi stripe.
orc.row.index.stride
10,000
Số rows giữa các index entries (>= 1,000).
orc.create.index
true
Có dùng index hay không
orc.bloom.filter.columns
-- Danh sách các tên cột được ngăn cách bởi dấy phẩy "," dùng cho Bloom filter
orc.bloom.filter.fpp
0.05
Tỷ lệ sai cho phép của Bloom filter. Lớn hơn 0.0 và bé hơn 1.0.

3. Dùng Vectorization

Vector hóa query execution giúp cải thiện hiệu năng của các phép toán như scans, aggregations, filters and joins bằng cách thực hiện chúng dưới dạng batch cho 1024 rows 1 lúc thay vì 1 rows

Ta có thể sử dụng dễ dàng bằng 2 setting sau

set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;

4. CBO - Cost-based optimization

Hive sẽ tối ưu kế hoạch thực thi câu query (cả về logical và physical) trước khi submit để thực thi nó.

Và Hive CBO giúp Hive tối ưu câu query dựa trên cost của câu query đó. Từ đó đưa ra các quyết định như thứ tự join như thế nào, kiểu join nào là tối ưu, mức độ thực thi song song, ...

Để dùng CBO ta có thể thiết lập các parameter sau trước khi bắt đầu query

set hive.cbo.enable=true;
set hive.compute.query.using.stats=true;
set hive.stats.fetch.column.stats=true;
set hive.stats.fetch.partition.stats=true;

Và ta phải chuẩn bị Column, table statistic cho CBO. Chú ý rằng, dữ liệu statistics của table chưa được tạo thì CBO sẽ bị tắt đi.

Dưới đây là 1 số câu lệnh để thu thập Column, Table Statistics

#1 Thu thập table statistics cho non-partitioned tables
ANALYZE TABLE [table_name] COMPUTE STATISTICS;

#2 Thu thập table statistics cho bảng được partition
ANALYZE TABLE [table_name] PARTITION(partition_column) COMPUTE STATISTICS;

#3 Thu thập column statistics
ANALYZE TABLE [table_name] COMPUTE STATISTICS for COLUMNS [comma_separated_column_list];
ANALYZE TABLE [table_name] PARTITION(partition_column) COMPUTE STATISTICS for COLUMNS [comma_separated_column_list];

Việc thu thập đầy đủ cả column statistics và table statistics là tốt nhất cho query performance.

5. ​Thiết kế Data Storage dùng Partitions

Partitions giúp cải thiện performance của câu Hive query bằng cách filter các partitioned columns. Từ đó ta chỉ phải scan dữ liệu trên 1 hoặc 1 số ít partition thỏa mãn điều kiện của filter. Một hệ thống lớn có thể có đến 10.000 partitions.

Ví dụ về partition

CREATE TABLE sale(id in, amount decimal)
PARTITIONED BY (xdate string, state string);

Sau đây là 1 số best practices với partitions

  • Không partition với unique ID
  • Kích thước trung bình của 1 partition nên lớn hơn hoặc bằng 1 GB
  • Một câu query không nên xử lý hơn 1000 partitions

Kết luận

Trên đây là 1 số cách đơn giản và hay được sử dụng để cải thiện tốc độ query của Hive.

Và cuối cùng, những cách đấy sẽ không thể có hiệu quả nếu câu SQL của ta không được tốt. Hãy viết những câu SQL tốt, giúp cho Hive query tốt hơn, nhanh hơn.

Tham khảo