從設(shè)計(jì)上來考慮HQL的優(yōu)化,會(huì)涉及到表設(shè)計(jì)、數(shù)據(jù)格式以及Job任務(wù)優(yōu)化等。
- 分區(qū)表設(shè)計(jì)
Hive 分區(qū)是最有效的優(yōu)化查詢性能的方法之一。使用分區(qū)過濾的查詢只加載特定分區(qū)(子目錄)的數(shù)據(jù),因此查詢性能肯定比不適用分組的查詢更快。分區(qū)鍵值選擇的優(yōu)劣通常是影響性能的重要因素。分區(qū)鍵值的選擇應(yīng)當(dāng)是非重復(fù)數(shù)據(jù)相對(duì)較少,以避免使用過多的子目錄。以下為分區(qū)鍵值選擇的通常做法:
- 按照日期和時(shí)間分區(qū): 當(dāng)數(shù)據(jù)和日期/時(shí)間列比較相關(guān),使用日期和時(shí)間,如年、月、日(甚至小時(shí))等作為分區(qū)鍵列,這些相關(guān)分區(qū)鍵值列為日期或者時(shí)間數(shù)據(jù)類型,如load_date, business_date, run_date等。
- 按照地域分區(qū): 當(dāng)數(shù)據(jù)和地理位置等信息相關(guān),使用國家、區(qū)域、州/省和城市作為分區(qū)鍵值。
- 按照業(yè)務(wù)邏輯分區(qū): 當(dāng)數(shù)據(jù)可以按照業(yè)務(wù)邏輯來進(jìn)行區(qū)分,可以使用部門、銷售區(qū)域、應(yīng)用、客戶等業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)列做為分區(qū)鍵列。
- Bucket表設(shè)計(jì)
與分區(qū)表類似,Bucket表把數(shù)據(jù)放在HDFS中不同的單獨(dú)的文件中。Bucket表可以加速數(shù)據(jù)取樣。同時(shí)當(dāng)關(guān)聯(lián)列同時(shí)是Bucket列時(shí),Bucket表可以改善關(guān)聯(lián)性能。由于Bucket列可以確保關(guān)聯(lián)列只出現(xiàn)在某個(gè)特定的Bucket里,所以Bucket列同時(shí)是關(guān)聯(lián)列時(shí),關(guān)聯(lián)性能會(huì)大大改善。較好選擇的Bucket列意味著關(guān)聯(lián)查詢的關(guān)聯(lián)列更大可能和Bucket列一致,因此通常把最有可能用于關(guān)聯(lián)或者過濾的列作為Bucket列。 - Index設(shè)計(jì)
使用Index用于改善性能是關(guān)系型數(shù)據(jù)庫最常用的調(diào)優(yōu)手段。Hive自0.7.0之后,也支持在表或者分區(qū)上創(chuàng)建索引。Hive中的索引提供一個(gè)基于Key的數(shù)據(jù)視圖,以及支持WHERE、GROUP BY 和JOIN等操作更好地進(jìn)行數(shù)據(jù)訪問。創(chuàng)建Index的示例為,
> CREATE INDEX idx_id_employee_id
> ON TABLE employee_id (employee_id)
> AS 'COMPACT'
> WITH DEFERRED REBUILD;
No rows affected (1.149 seconds)
COMPACT索引 保存索引列的值和它的Block ID。
BITMAP索引(自0.8.0后支持)適用于列值為較少變量值的情況。以下為BITMAP索引的示例,
> CREATE INDEX idx_gender_employee_id
> ON TABLE employee_id (gender_age)
> AS 'BITMAP'
> WITH DEFERRED REBUILD;
No rows affected (0.251 seconds)
WITH DEFERRED REBUILD選項(xiàng),指定索引不會(huì)立即重建。為了重建索引,我們可以執(zhí)行 ALTER INDEX ...REBUILD命令。
ALTER INDEX idx_id_employee_id ON employee_id REBUILD;
No rows affected (111.413 seconds)
ALTER INDEX idx_gender_employee_id ON employee_id REBUILD;
No rows affected (82.23 seconds)
一旦索引創(chuàng)建成功,每個(gè)索引會(huì)對(duì)應(yīng)創(chuàng)建一個(gè)索引表,該索引表的命名格式為 <database_name><table_name><index_name>_:
> SHOW TABLES '*idx*';
+-----------+---------------------------------------------+-----------+
|TABLE_SCHEM| TABLE_NAME | TABLE_TYPE|
+-----------+---------------------------------------------+-----------+
|default |default__employee_id_idx_id_employee_id__ |INDEX_TABLE|
|default |default__employee_id_idx_gender_employee_id__|INDEX_TABLE|
+-----------+---------------------------------------------+-----------+
索引表包含索引列、_bucketname和_off_sets,共三列。如下例所示,
> DESC default__employee_id_idx_id_employee_id__;
+--------------+----------------+----------+
| col_name | data_type | comment |
+--------------+----------------+----------+
| employee_id | int | |
| _bucketname | string | |
| _offsets | array<bigint> | |
+--------------+----------------+----------+
3 rows selected (0.135 seconds)
> SELECT * FROM default__employee_id_idx_id_employee_id__;
+--------------+------------------------------------------------------+
| employee_id | _bucketname | _offsets |
+--------------+------------------------------------------------------+
| 100 | .../warehouse/employee_id/employee_id.txt | [0] |
| 101 | .../warehouse/employee_id/employee_id.txt | [66] |
| 102 | .../warehouse/employee_id/employee_id.txt | [123] |
| ... | ... ... | ... |
+--------------+-------------------------------------------+----------+
25 rows selected (0.219 seconds)
刪除索引的命令如下所示,刪表不會(huì)刪相關(guān)索引。
DROP INDEX index_name ON table_name
- skewed/temporary 表的使用
自Hive 0.10.0之后,HQL開始支持創(chuàng)建skewed表。通過把skewed數(shù)據(jù)區(qū)分開來自動(dòng)放入專門的文件和文件夾內(nèi),查詢就只訪問或者不訪問這些數(shù)據(jù),這樣在查詢中用到的文件和分區(qū)文件夾數(shù)量變小,從而改善性能。以下為創(chuàng)建skewed表示例,
> CREATE TABLE sample_skewed_table (
> dept_no int,
> dept_name string
> )
> SKEWED BY (dept_no) ON (1000, 2000); -- Specify value skewed
No rows affected (3.122 seconds)
> DESC FORMATTED sample_skewed_table;
+-----------------+------------------+---------+
| col_name | data_type | comment |
+-----------------+------------------+---------+
| ... | ... | |
| Skewed Columns: | [dept_no] | NULL |
| Skewed Values: | [[1000], [2000]] | NULL |
| ... | ... | |
+-----------------+------------------+---------+
33 rows selected (0.247 seconds)
臨時(shí)表(temporary table)可以把多次使用的中間結(jié)果單獨(dú)存放,以節(jié)省重建這些共享共通數(shù)據(jù)集所消耗的資源。另外也可以把它存放在SSD或者內(nèi)存中以改善性能。