1. 程式人生 > >阿里分析型資料庫AnalyticDB優化點

阿里分析型資料庫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子句中的等值條件列(通常是一級分割槽列)作為聚集列。