閱讀920 返回首頁    go 阿裏雲


7.4 查詢SQL優化__第七章 性能優化和診斷_使用手冊_分析型數據庫-阿裏雲

單表查詢

索引和掃描選擇

分析型數據庫默認為全索引,對於查詢的多個條件分別檢索索引,得出多個結果集(行集合),然後采用流式歸並算法得出滿足組合條件的最終結果集。索引的性能主要受key的分布影響,包括:cardinality(散列程度),範圍查詢的記錄數/表記錄數。

但是在以下四種情況下,索引性能較差。

  • 範圍查詢(或等值查詢)篩選能力差,即滿足條件的記錄數/表總記錄超過10%。
  • 不等於條件查詢(不包括not null)。
  • 中綴或後綴查詢,例如 like ‘%abc’ 或like ‘%abc%’。
  • AND 條件中某一條件具有高篩選能力,其他條件走索引性能比掃描性能差。

對於以上四種情況,掃描性能反而比索引的性能好。用戶通過加hint的方法強製查詢不走索引。

Hint格式如下:

  1. /*+ no-index=[table1.x;table2.x;y]*/。

例如:

  1. /*+ no-index=[table1.time]*/ select * from table1 where x= 3 and time between 0 and 10000

表示強製條件time between 0 and 10000走掃描。計算引擎首先檢索列x的索引,得出滿足條件x=3的行集合,然後讀取每行所對應的time列數據,如果滿足time between 0 and 10000,則將該行數據加入返回結果。

二級分區查詢優化

一級分區包含多個二級分區;計算時,每個二級分區依次執行條件查詢,並將所有二級分區的結果進行匯總。由於每個二級分區都要參與所有條件篩選(索引查詢),當二級分區較多時,查詢性能較差。如果能夠預知數據的分布,確定二級分區的範圍,可以在查詢條件中增加二級分區列條件,這樣可以快速過濾無效的二級分區,減少搜索範圍。

例子:

  1. select * from table where id = 3 and time between ‘2016-04-01 00:00:00’ and ‘2016-04-01 12:00:00’;

如果根據業務場景確認滿足time between ‘2016-04-01 00:00:00’ and ‘2016-04-01 12:00:00’ 的二級分區列為20160401,則可以將該SQL改寫為:

  1. select * from table where id = 3 and time between ‘2016-04-01 00:00:00’ and ‘2016-04-01 12:00:00’ and pid = 20160401;

pid為二級分區列名。

條件改寫

當SQL中條件為函數時,無法走索引過濾,自動走掃描。在大多數情況下,性能會比較差,因此盡量改寫條件去除函數。例如以下SQL:

  1. Select * from table where year(date_test) > 1990

應該改為

  1. Select * from table where date_test > ‘1990-00-00’

多表查詢

首先我們來複習一下可加速join的條件:

對於COMPUTENODE Local/Merge計算模式的表Join查詢,需要滿足以下幾個條件:

  • 連接計算的所有事實表必須在同一個表組。
  • 所有事實表的一級分區數相同。
  • 事實表Join時, on條件必須包含分區列且必須是等值查詢,其他列無限製。
  • Left join時,右表是事實表時,左表不能是維度表。

子查詢使用

對於子查詢,分析型數據庫會首先執行子查詢,並將子查詢的結果保存在內存中,然後將該子查詢作為一個邏輯表,執行條件篩選。由於子查詢沒有索引,所有條件篩選走掃描。因此如果子查詢結果較大時,性能比較差;反之當子查詢結果集較小時,掃描性能反而超過索引查詢。

對於join查詢,由於分析型數據庫默認采用hash join算法,如果其中一張表結果集(條件篩選後)較大時,掃描性能會比索引差很多,因此盡量不要采用子查詢。例如以下SQL:

  1. 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的條數較多時,應改成:

  1. Select A.id from table1 A join table2 B on A.id = B.id where B.y = 6 and A.x=5

一個例外情況是,當結果集較大的表是實時表,應盡量采用子查詢。原因在於,實時表的最新數據(基線合並後寫入的數據),索引能力很弱,查詢性能非常差。子查詢可以減少搜索範圍,性能反而更好。

小表廣播/Full MPP Mode查詢優化

Full MPP Mode 與COMPUTENODE Local/Merge模式選擇

COMPUTENODE Local/Merge模式是分析型數據庫支持的一種極速查詢模式,通過對用戶SQL的有效甄別,快速判斷是否和數據分布相匹配,從而達到優化數據shuffle邏輯,下沉大量計算操作的目的。

使用Full MPP Mode一般需用戶使用Hint顯示指定。

用戶也可通過在查詢hint中指定來強製查詢使用MPP或COMPUTENODE模式。典型使用COMPUTENODE Local/Merge模式的場景有:

  • 不包含表連接或者子查詢的任意查詢。
  • 表連接條件為等值條件且連接列均為一級分區列的任意查詢。
  • 子查詢包含了分區列的的groupby操作的任意查詢。
小表廣播

小表廣播是基於COMPUTENODE Local/Merge模式擴展出的一種支持子查詢內部不包含分區列的join操作的查詢模式。典型的使用場景有:

  • 非分區列的連接。如:
  1. select name from student1 a join student2 b on a.name = b.name

兩個表分區列都為id,由於表連接為非分區列,該查詢不能使用模式。若student2表數據量不超過3萬條,使用小表廣播後,查詢可以改寫為:

  1. select name from student1 a join (select /*+broadcast=true*/ name from student2) b on a.id = b.id

即可通過COMPUTENODE模式進行快速查詢。

  • 子查詢內不包含分區列。如:
  1. select name from student1 where name in (select name from student2 where id = 10)

該查詢無法使用COMPUTENODE模式計算出正確結果,若id=10的name記錄數不大於3萬條,可修改為小表廣播後:

  1. select name from student1 where name in (select /*+broadcast=true*/ name from student2 where id = 10)
Full MPP Mode最優寫法

當查詢無法使用COMPUTENODE模式進行查詢時,對使用MPP查詢的SQL進行必要的修改,可以很大程度的提高查詢的速度。以TPC-H測試中第2個查詢為例,原查詢為:

  1. select
  2. s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment
  3. from
  4. (select p_partkey, p_mfgr from part p where p_size = 15 and p_type like '%BRASS') inner join partsupp ps on p_partkey = ps_partkey
  5. inner join supplier s on s_suppkey = ps_suppkey
  6. inner join (
  7. select p_partkey as min_p_partkey, min(ps_supplycost) as min_ps_supplycost from part p
  8. inner join partsupp ps on p_partkey = ps_partkey
  9. inner join supplier s on s_suppkey = ps_suppkey
  10. inner join nation n on s_nationkey = n_nationkey
  11. inner join region r on n_regionkey = r_regionkey and r_name = 'EUROPE'
  12. group by p_partkey
  13. )A on ps_supplycost = A.min_ps_supplycost and p_partkey =A.min_p_partkey
  14. inner join nation n on s_nationkey = n_nationkey
  15. inner join region r on n_regionkey = r_regionkey and r_name = 'EUROPE'
  16. order by
  17. s_acctbal desc,
  18. n_name,
  19. s_name,
  20. p_partkey
  21. limit 100

將小表結果進行前置,進行join的reordering後,查詢性能提高了近1倍

  1. /*+engine=MPP*/select
  2. s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment
  3. from
  4. region r
  5. inner join nation n on n_regionkey = r_regionkey and r_name = 'EUROPE'
  6. inner join supplier s on s_nationkey = n_nationkey
  7. inner join partsupp ps on s_suppkey = ps_suppkey
  8. inner join (select p_partkey, p_mfgr from part p where p_size = 15 and p_type like '%BRASS') p on p_partkey = ps_partkey
  9. inner join (
  10. select p_partkey as min_p_partkey, min(ps_supplycost) as min_ps_supplycost from region r
  11. inner join nation n on n_regionkey = r_regionkey and r_name = 'EUROPE'
  12. inner join supplier s on s_nationkey = n_nationkey
  13. inner join partsupp ps on s_suppkey = ps_suppkey
  14. inner join part p on p_partkey = ps_partkey
  15. group by p_partkey
  16. )A on ps_supplycost = A.min_ps_supplycost and p_partkey =A.min_p_partkey
  17. order by
  18. s_acctbal desc,
  19. n_name,
  20. s_name,
  21. p_partkey
  22. limit 100

最後更新:2016-11-23 16:04:20

  上一篇:go 7.3 表結構優化__第七章 性能優化和診斷_使用手冊_分析型數據庫-阿裏雲
  下一篇:go 7.5 實時寫入優化__第七章 性能優化和診斷_使用手冊_分析型數據庫-阿裏雲