【文末彩蛋】數據倉庫服務 GaussDB(DWS)單點性能案例集錦

摘要:介紹了13種GaussDB(DWS)單點性能的案例。

1、數據傾斜

1.1 問題描述

某局點SQL執行慢,涉及大表的SQL執行不出來結果。html

1.2 分析過程

數據傾斜在不少方面都會有體現:node

1)gs_ssh –c 「df -h」sql

查看各個數據磁盤的利用率,會有不均衡的現象。正常狀況下,利用率最高和利用率最高的磁盤空間相差不大,若是磁盤利用率相差超過了5%就要引發重視。數據庫

2)經過等待視圖查看做業的運行狀況,發現做業老是等待部分DN,或者個別DN。緩存

Select wait_status, count(*) cnt from pgxc_thread_wait_status where wait_status not like ‘%cmd%’ and wait_status not like ‘%none%’ and wait_status not like ‘%quit%’ group by 1 order by 2 desc;

3)慢語句的explain performance顯示,基表scan的時間和行數各個DN之間不均衡。併發

基表scan的時間最快的dn耗時5ms,最慢的dn耗時1173msdom

數據最多的dn有22831616行,其餘dn都是0行,數據有嚴重傾斜。ssh

4)經過傾斜檢查接口能夠發現數據傾斜。分佈式

select table_skewness('store_sales');

select table_distribution('public','store_sales');

5)經過資源監控發現,個別節點的CPU/IO明顯比其餘節點高。函數

1.3 問題根因

GaussDB當前支持Hash表和複製表兩種分佈方式。默認建立的表是Hash分佈的,若是不指定分佈鍵,則選擇表的第一列做爲分佈鍵。那麼這種狀況就可能存在傾斜的。

傾斜形成的負面影響很是大。

首先,SQL的性能會很是差,由於數據只分布在部分DN,那麼SQL運行的時候就只有部分DN參與計算,沒有發揮分佈式的優點。

其次,會致使資源傾斜,尤爲是磁盤。可能部分磁盤的空間已經接近極限,可是其餘磁盤利用率很低。

可能出現部分節點CPU太高等等問題。

1.4 解決詳情

如何找到傾斜的表:

1)在庫中表個數少於1W的場景,直接使用傾斜視圖查詢當前庫內全部表的數據傾斜狀況。

SELECT * FROM pgxc_get_table_skewness ORDER BY totalsize DESC;

2)在庫中表個數很是多(至少大於1W)的場景,因PGXC_GET_TABLE_SKEWNESS涉及全庫查並計算很是全面的傾斜字段,因此可能會花費比較長的時間(小時級),建議參考PGXC_GET_TABLE_SKEWNESS視圖定義,直接使用table_distribution()函數自定義輸出,減小輸出列進行計算優化,例如:

SELECT schemaname,tablename,max(dnsize) AS maxsize, min(dnsize) AS minsize 
FROM pg_catalog.pg_class c 
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
INNER JOIN pg_catalog.table_distribution() s ON s.schemaname = n.nspname AND s.tablename = c.relname 
INNER JOIN pg_catalog.pgxc_class x ON c.oid = x.pcrelid AND x.pclocatortype = 'H' 
GROUP BY schemaname,tablename;

表的分佈鍵的選擇方法:

1)這個列的distinct值比較大,而且沒有明顯的數據傾斜。也能夠把多列定義成分佈列。

怎麼看distinct的大小?

select count(distinct column1) from table;

怎麼看數據是否是有傾斜?

select count(*) cnt, column1 from table group by column1 order by cnt limint 100;

2)選用常常作JOIN字段/group by的列,能夠減小STREAM運算。

3)很差的實踐:

分佈列用默認值(第一列)

分佈列用sequence自增生成

分佈列用隨機數生成(除非任意列,或者任意兩列的組合作分佈鍵都是傾斜的,通常不選用這種方法)。

2、統計信息未收集

2.1 問題描述

2.2 分析過程

1. 經過explain verbose/explain performance打印語句的執行計劃

2. 執行計劃中會有語句未收集統計信息的告警,而且一般E-rows估算很是小。

3. 上述例子中,在打印的執行計劃中有Warning提示信息,提示有哪些列在這個執行計劃中用到了,可是這些列沒有統計信息。

在CN的pg_log日誌中也有會有相似的Warning信息。

同時,E-rows會比實際值小不少。

2.3 問題根因

優化器是基於代價的優化 (Cost-Based Optimization,簡稱CBO)。在這種優化器模型下,數據庫根據表的元組數、字段寬度、NULL記錄比率、distinct值、MCV值、HB值等表的特徵值,以及必定的代價計算模型,計算出每個執行步驟的不一樣執行方式的輸出元組數和執行代價(cost),進而選出總體執行代價最小/首元組返回代價最小的執行方式進行執行。

統計信息是優化器生成執行計劃的基礎,沒有收集統計信息,優化器生成的執行計劃會很是差,若是統計信息未收集,會致使多種多樣表現形式的性能問題。例如,等值關聯走NestLoop,大表broadcast,集羣CPU持續增高等等問題。

2.4 解決詳情

週期性地運行ANALYZE,或者在對錶的大部份內容作了更改以後立刻執行analyze。

3、語句不下推

3.1 問題描述

3.2 分析過程

1)經過explain verbose打印語句執行計劃

2)上述執行計劃中有__REMOTE關鍵字,這就代表當前的語句是不下推執行的。

3)不下推語句在pg_log中會打印不下推的緣由。上述語句在CN的日誌中會找到相似如下的日誌:

3.3 問題根因

目前最新版本能夠支持絕大多數經常使用函數的下推。

不下推函數的場景主要出如今自定義函數屬性定義錯誤的場景。

不下推語句的執行方式沒有利用分佈式的優點,他的執行過程至關於把大量的數據和計算過程聚集到一個節點上去作,所以性能每每很是差。

3.4 解決詳情

審視用戶自定義函數的provolatile屬性是否認義正確。若是定義不正確,要修改對應的屬性,使它可以下推執行。

具體判斷方法能夠參考以下說明:

函數相關的全部屬性都在pg_proc這張系統表中能夠查到。其中與函數可否下推相關的兩個屬性是provolatile 和 proshippable。

其中provolatile是繼承自PG的字段,他的本質含義是描述函數是IMMUTABLE/STABLE/VOLATILE的。

簡單來說,若是一個函數對於一樣的輸入,必定有相同的輸出,那麼這類函數就是IMMUTABLE的,例如絕大部分的字符串處理函數。

若是一個函數的返回結果在一個SQL語句的調用過程當中,結果是相同的,那麼他就是STABLE的。例如時間相關的處理函數,他的最終顯示結果可能與具體的GUC參數相關(例如控制時間顯示格式的參數),這類函數都是STABLE的。

若是一個函數的返回結果可能隨着每一次的調用而返回不一樣的結果。例如nextval,random這種函數,每次調用結果都是不可預期的,那麼他就是VOLATILE的。

4、not in 和 not exists

4.1 問題描述

客戶的SQL語句執行慢,執行計劃中有NestLoop

4.2 問題定位

1.首先觀察SQL語句中有not in 語法

2.執行計劃中有NestLoop

4.3 問題根因

NestLoop是致使語句性能慢的主要緣由。

Hashjoin只能作等值關聯。NestLoop的條件中有or條件,因此沒法用Hashjoin求解。

致使出現這個現象的緣由是由not in的語義決定的(具體能夠參考外網關於not in 和 not exists的介紹)。

4.4 解決詳情

大多數場景下,客戶須要的結果集實際上是能夠經過not exists得到的,所以上述語句能夠經過修改將not in 修改成not exists。

5、未分區剪枝

5.1 問題描述

三條sql查詢慢,查詢的分區表總共185億條數據,查詢條件中沒有涉及分區鍵

select passtime from 表 where passtime<'2020-02-19 15:28:14' and passtime>'2020-02-18 15:28:37' order by passtime desc limit 10; 
select max(passtime) from 表 where passtime<'2020-02-19 15:28:14' and passtime>'2020-02-18 15:28:37';

列存表,分區鍵爲createtime,哈希分佈鍵爲motorvehicleid

5.2 分析過程

1.和客戶確認部分業務慢,慢的業務中都涉及到了同一張表tb_motor_vehicle

2.和客戶收集幾個典型的慢sql,分別打印執行計劃

從執行計劃中能夠看出來,兩條sql的耗時都集中在Partitioned CStore Scan on public.tb_motor_vehicle列存表的分區掃描上

3.和客戶確認,該表的分區鍵爲createtime,而涉及到的sql中無任何createtime的篩選和過濾條件,基本能夠確認是因爲慢sql的計劃沒有走分區剪枝,致使了全表掃描,對於185億條數據量的表,全表掃描性能會不好。

4.經過在篩選條件中增長分區鍵過濾條件,優化後的sql和執行計劃以下:

SELECT passtime FROM tb_motor_vehicle WHERE createtime > '2020-02-19 00:00:00' AND createtime < '2020-02-20 00:00:00' AND passtime > '2020-02-19 00:00:00' AND passtime < '2020-02-20 00:00:00' ORDER BY passtime DESC LIMIT 10000;

性能從十幾分鍾,優化到了12秒左右,性能有明顯提高

5.3 問題根因

慢sql過濾條件中未涉及分區字段,致使執行計劃未分區剪枝,走了全表掃描,性能嚴重裂化

5.4 解決詳情

在慢sql的過濾條件中增長分區篩選條件,避免走全表掃描

6、行數估算太小,走了nestloop

6.1 問題描述

查詢語句執行慢,卡住沒法返回結果

sql特色是2-3張表left join,而後經過select查詢結果,執行計劃以下:

6.2 分析過程

1.排查當前的IO,內存,CPU使用狀況,沒有發現資源佔用高的狀況

2.查看慢sql的線程等待狀態

select * from pg_thread_wait_status where query_id=’149181737656737395’;

根據線程等待狀態,並無出現都在等待某個DN的狀況,初步排除中間結果集偏斜到了同一個DN的狀況。

3.到相應的實例節點上,打印等待狀態爲none的線程堆棧信息以下:

gstack 14104

經過反覆打印堆棧信息,發現堆棧在變化,並無hang死,因此初步判斷該問題未性能慢的問題,堆棧中有VecNestLoopRuntime,以及結合執行計劃,初步判斷是因爲統計信息不許,優化器評估結果集較少,計劃走了nestloop致使性能降低。

4.對錶執行analyze後性能並無太大改善

5.對sql增長hint關閉索引,讓優化器強行走hashjoin,發現hint功能沒有生效,緣由是hint沒法改變子查詢中的計劃

6.經過set enable_indexscan = off;執行計劃被改變,走了Hash Left Join,慢sql在3秒左右跑出結果,知足客戶需求。

6.3 問題根因

優化器在選擇執行計劃時,對結果集評估較小,致使計劃走了nestloop,性能降低

6.4 解決詳情

經過set set enable_indexscan = off;關閉索引功能,讓優化器生成的執行計劃不走nestloop,而走Hashjoin

7、表數據膨脹,未清理髒數據

7.1 問題描述

數據庫性能時快時慢問題

GaussDB 數據庫性能時快時慢問題,原先幾秒鐘的sql,目前20幾秒出來,致使前臺IOC頁面數據加載超時,沒法對用戶提供圖表顯示

7.2 分析過程

1. raid卡緩存策略未開啓、CPU開啓了節能模式,查詢並未開啓

/opt/MegaRAID/MegaCli/MegaCli64 -LDinfo -Lall –aAll |grep 'Write Cache'(root用戶)
cat /proc/cpuinfo |grep MHz

2.和客戶確認是部分業務慢,能夠提供部分慢sql,打印執行計劃,耗時主要在index scan上,懷疑是IO爭搶致使,經過監控IO,發現並無IO資源使用瓶頸。

3.查詢當前活躍sql,發現有大量的create index語句,須要和客戶確認該業務是否合理

select * from pg_stat_activity where state !=’idle’ and usename !=’omm’;

4.根據執行計劃,發如今部分DN上耗時較高,查詢表的傾斜狀況,並未發現有傾斜的狀況

select table_skewness(‘ioc_dm.m_ss_index_event’);

5.檢查內存相關參數,設置不合理,須要優化

單節點總內存大小爲256G

max_process_memory爲12G,設置太小
shared_buffers爲32M,設置太小
work_mem:CN:64M 、DN:64M
max_active_statements: -1(不限制併發數)

設置方式以下:

gs_guc set -Z coordinator -Z datanode -N all -I all -c "max_process_memory=25GB"
gs_guc set -Z coordinator -Z datanode -N all -I all -c "shared_buffers=8GB"
gs_guc set -Z coordinator -Z datanode -N all -I all -c "work_mem=128MB"

6.進一步分析掃描慢的緣由,發現表數據膨脹嚴重,對其中一張8G大小的表,總數據量5萬條,作完vacuum full後大小減少爲5.6M

7.3 問題根因

1.大量表頻繁增刪改,未及時清理,致使髒數據過多,表數據膨脹,查詢慢

2.交付時,內存參數設置不合理

7.4 解決詳情

1.對業務涉及到的經常使用的大表,執行vacuum full操做,清理髒數據;

2.設置GUC內存參數

8、「in 常量」優化

8.1 問題描述

簡單的大表過濾的SQL語句中有一個「in 常量」的過濾條件,常量的個數很是多(約有2000多個),基表數據量比較大,SQL語句執行不出來。

8.2 分析過程

1.打印語句的執行計劃:

2.執行計劃中,in條件仍是做爲普通的過濾條件存在。這種場景下,最優的執行計劃應該是將「in 常量」轉化爲join操做性能更好。

8.3 問題根因

執行計劃中,in條件仍是做爲普通的過濾條件存在。這種場景下,最優的執行計劃應該是將「in 常量」轉化爲join操做性能更好。

8.4 解決詳情

qrw_inlist2join_optmode能夠控制把「in 常量」轉join的行爲。默認是cost_base的。若是優化器估算不許,可能會出現須要轉化的場景沒有作轉化,致使性能較差。

這種狀況下能夠經過設置qrw_inlist2join_optmode爲rule_base來規避解決。

9、相關子查詢1

9.1 問題描述

用戶的SQL性能差,執行計劃中有SubPlan的關鍵字

9.2 分析過程

執行計劃中有SubPlan,這類語句的性能每每比較差。

9.3 問題根因

執行計劃中有SubPlan的語句每每性能比較差,這是由於,引用SubPlan結果的算子可能須要反覆的調用獲取這個SubPlan的值,即SubPlan如下的結果要重複執行不少次。

9.4 解決詳情

這類問題一般經過改寫SQL來規避。每每這種場景的SQL語句的改寫是比較困難,並且很容易出現改寫後的結果不一致問題。

因爲咱們在比較高的版本上已經支持了不少場景想的SubPlan的自動轉化爲join操做,所以一種比較方便的思路是打印他在高版本下的執行計劃(explain verbose),而後根據explain verbose 演繹出來改寫後的SQL語句。

以上述爲例,他在高版本的執行計劃以下:

那麼根據上述信息,SQL語句能夠改寫爲:

爲了確認改寫後的語句與原來的語句是等價的,能夠再次打印改寫後的執行計劃,對比:

10、相關子查詢2

10.1 問題描述

UPDATE場景下出現了SubPlan致使語句執行性能差

10.2 分析過程

上述執行計劃中有SubPlan,這類語句的性能每每比較差。

10.3 問題根因

執行計劃中有SubPlan的語句每每性能比較差,緣由與1.9章節案例相似。

10.4 解決詳情

上述問題能夠經過特定的改寫方法來解決:

11、單表點查性能差

11.1 問題描述

單表查詢的場景下,客戶預期1s之內返回結果,實際執行耗時超過10s

11.2 分析過程

1. 經過抓取問題SQL的執行信息,發現大部分的耗時都在「CStore Scan」

2. 分析出問題的場景:基表是一張十億級別的表,每晚有批量增量數據入庫,同時會有少許的數據清洗的工做。白天會有高併發的查詢操做,查詢不涉及表關聯,而且返回結果都不大。

11.3 問題根因

這種場景屬於行列存表選擇錯誤致使的問題。這種場景應該使用行存表+btree索引。

11.4 解決詳情

調整表定義,表修改成行存表。同時創建btree索引,索引創建的原則:

  • 基於充分分析客戶SQL的背景下去創建索引。
  • 索引要創建的剛恰好,不要有冗餘
  • 創建組合索引時候,要把過濾性比較好的列往前放
  • 儘量多的過濾條件都用到索引

12、NestLoop+indexscan的適用場景

12.1 問題描述

某客戶反饋兩個表的關聯要去秒級返回,其中大表有2.7T,小表有100GB左右,查詢結果通常都不大,過濾條件中有過濾性比價好的條件。

12.2 分析過程

1. 原始的執行計劃:

2. 能夠看到兩個表關聯走了HashJoin,主要的耗時在基表掃描和HashJoin操做上。

12.3 問題根因

主要的耗時點是在Hashjoin 和基表掃描上,這種狀況下能夠考用NestLoop+indexScan的計劃。

這種計劃會把join條件下推到基表掃描上,而後利用基表的索引,提早把數據過濾掉。

12.4 解決詳情

因爲NestLoop+indexScan的計劃有一些約束:

1. Join的時候不能有stream(不能經過stream來傳遞join條件的下推)

2. 大表上要有合適的索引。

修改後的執行計劃以下:

文末彩蛋:

臨近華爲雲3月開年採購季

據內部可靠消息,採購季中數倉GaussDB(DWS)

包月包年都將有重大優惠,對企業用戶尤其友好!!!

PS:關注數倉GaussDB(DWS)公衆號,get最新最全的產品資訊和數倉黑科技,更有超多活動,福利不停歇!歡迎訪問數倉GaussDB(DWS)開發者論壇,產品特性隨時交流,求助問題還有專家在線實時答疑哦~掃描下方二維碼關注我哦↓↓↓

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索