阿里分析型資料庫AnalyticDB優化點
參考官方文件地址:https://help.aliyun.com/document_detail/98793.html
由於工作中有用到AnalyticDB,只有很好的瞭解AnalyticDB才能做好優化工作!有些優化點跟MySQL差不多,只是多了分散式的特性,結合工作的應用自己總結了以下幾個點:
1.SQL編寫能簡單儘量簡單,比如單表查詢肯定優於多表級聯和子查詢。
2.儘量不要用select *,即沒必要返回不需要的列。
3.當SQL包含多個查詢條件時,優先選擇高篩選條件,其他條件可以通過掃描實現。
這是因為AnalyticDB內部採用列存方式,通過單列高效過濾後,可直接通過內部記錄指標掃描其他列值,減少其他列的索引查詢開銷。
例如:
time條件通過內部掃描
Hint表示強制time>='2010-01-01 00:00:00’條件走掃描。
/* +no-index=[tab1.time] */
select c1,c2 from tab1 where c1=3 and time >='2010-01-01 00:00:00';
首先通過c1=3的條件可以快速定位到相關的資料,因此c1走索引。如果單獨使用“time >=‘2010-01-01 00:00:00’”條件的話返回的記錄數非常大,這時候跟據AnalyticDB的特性,time沒必要走索引了。
計算引擎首先檢索列c1的索引,得出滿足條件c1=3的行集合,然後讀取每行所對應的time列資料。如果滿足time>=‘2010-01-01 00:00:00’,則將該行資料加入返回結果。
不等於條件通過內部掃描
增加no-indexHint,使不等於條件通過內部掃描執行,SQL示例如下:
/* +no-index=[tab1.c2] */
select c1,c2 from tab1 where c1=3 and c2<>100;
like條件通過內部掃描
中綴或字尾查詢,例如:like '%abc’或like ‘%abc%’。
增加no-indexHint,使like條件通過內部掃描執行,更加快速地查詢有效記錄,SQL示例如下:
/* +no-index=[tab1.c3] */
select c1,c2 from tab1 where c1=3 and c3 like ‘%abc%’;
4.避免索引失效,應該儘量避免下面這些情況導致索引失效:
- 函式轉換(列)
- 型別轉換
- like條件,例如:like ‘%abc%’
5.去掉不必要的is not null條件判斷。
6.儘量不用子查詢,如果可以的話改成表關聯查詢。
處理帶有子查詢的Select時,AnalyticDB首先執行子查詢,並將子查詢的結果儲存在記憶體中,然後將該子查詢作為一個邏輯表,執行條件篩選。
由於子查詢沒有索引,所有條件篩選都要進行掃描。因此如果子查詢結果較大時,效能比較差。反之當子查詢結果集較小時,掃描效能會超過索引查詢。
對於join查詢,由於AnalyticDB預設採用hash join演算法,如果其中一張表結果集(條件篩選後)較大時,掃描效能會必索引差很多,因此儘量不要採子查詢。例如以下SQL:
Select A.id from table1 A join
(select table2.id from table2 where table2.y = 6) B
on A.id= B.id where A.x=5
當滿足條件x=5 和y=6的條數較多時,應改成:
Select A.id from table1 A join table2 B
on A.id = B.id
where B.y = 6 and A.x=5
7.多表關聯
-
普通表join普通表,儘量包含分割槽列join條件,如果不包含則,儘量通過where條件過濾掉多餘的資料。
-
維度表join普通表,沒有限制。
多表關聯查詢where條件中,需要明確寫明每一個表的過濾條件。通常我們在傳統資料庫中,都是通過索引欄位關聯來快速檢索資料。如下SQL:
Select count(*)
from customer_table C join
order_table O on C.customer_id= O.customer_id
where O.order_time between'2018-07-20 10:00:11'
and '2018-09-30 10:00:11'
and O.order_amount=100;
在明確t2與t1表都有同樣的time和type過濾條件情況下,建議修改為如下SQL:
Select count(*)
from t1 join t2 on t1.id=t2.id
where t1.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59'
and t1.type= 100
and t2.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59'
and t2.type=100
8.合理的使用一級分割槽,如果資料量非常大可以考慮二級分割槽。
AnalyticDB一級分割槽表採用HASH分割槽,可指定任意一列(不支援多列)作為分割槽列。HASH分割槽通過標準CRC演算法計算出CRC值,並將CRC值與分割槽數作模計算,得出每條記錄的分割槽號。空值的HASH值與字串-1相同。以下按照優先順序從高到底列出一級分割槽列的選擇依據。
1.選擇值分佈均勻的列作為分割槽列,請勿選擇分佈不均勻的列作為分割槽列。
2.建議選擇一級分割槽列的資料型別為tinyint、smallint、int、bigint或者varchar。
3.如果是多個普通表(不包括維度表)JOIN,則選擇參與JOIN的列作為分割槽列。
如果是多列JOIN ,則根據查詢重要程度或查詢效能要求(例如:某SQL的查詢頻率特別高)來選擇分割槽列,以保證基於分割槽列的JOIN具有較好的查詢效能。
4.選擇GROUP BY或DISTINCT包含的列作為分割槽列。
5.如果常用的SQL包含某列的等值或IN查詢條件,則選擇該列作為分割槽列。以下列子則選擇id作為分割槽列。
select * from table where id=123 and …;
select * from table where user in(1, 2,3);
9.使用聚合列,使用的條件如下:
-
主要或大多數的查詢條件中均包括某一列,且該查詢條件具有較高的篩選率,則選擇該列作為聚集列。
-
Join子句中的等值條件列(通常是一級分割槽列)作為聚集列。