數據庫性能調優之始: analyze統計信息


摘要:本文簡單介紹一下什么是統計信息、統計信息記錄了什么、為什么要收集統計信息、怎么收集統計信息以及什么時候收集統計信息。

1 WHY:為什么需要統計信息

1.1 query執行流程

下圖描述了GaussDB的SQL引擎從接收客戶端SQL語句到執行SQL語句需要經歷的關鍵步驟,以及各個流程中可能對執行產生影響的因素

1) 詞法&語法解析

按照約定的SQL語句規則,把輸入的SQL語句從字符串轉化為格式化結構(Stmt),如果SQL語句存在語法錯誤,都會在這個環節報錯。

2) 語義解析

語義解析類似一個翻譯器,把外部輸入的可視化的對象翻譯為數據庫內部可識別的對象(比如把Stmt中以字符串記錄的表名稱轉化為數據庫內部可識別的oid),如果語句存在語義錯誤(比如查詢的表對象不存在),數據庫會在這個環節報錯。

3) 查詢重寫

根據規則將“語義解析”的輸出等價轉化為執行上更為優化的結構,比如把查詢語句中的視圖逐層展開至最低層的表查詢。

4) 查詢優化

數據庫確認SQL執行方式、生成執行計划的過程

5) 查詢執行

根據執行計划執行SQL並輸出結果的過程

整個執行流程中,優化器決定了查詢語句的具體執行方式,對SQL語句的性能起着關鍵性的作用。數據庫查詢優化器分為兩類:基於規則的優化器(Rule-Based Optimizer,RBO) 和基於代價的優化器(Cost-Based Optimizer,CBO)。RBO是一種基於規則的優化,對於指定的場景采用指定的執行方式,這種優化模型對數據不敏感;SQL的寫法往往會影響執行計划,不了解RBO的細則的人員開發的SQL性能不可控,因此RBO逐漸被拋棄,目前GaussDB等數據庫廠商的優化器都是CBO模型。CBO模型是根據SQL語句生成一組可能被使用的執行計划,並估算出每種執行計划的代價,最終選擇選擇一個代價最小的執行方式。

1.2 CBO模型

數據庫執行SQL語句的時候,會把執行拆分為若干步驟,如下SQL

select *
from t1 join t2 on t1.a=t2.b
where t1.b = 2 and t2.a = 3;

在具體執行的時候會拆分為表掃描和表關聯兩個主要查詢動作。這兩個查詢動作都存在多種執行方式,比如表掃描均存在SeqScan、IndexScan、IndexOnlyScan、BitmapScan等多種執行方式、表關聯存在NestLoop、HashJoin、MergeJoin三種執行方式,那么在具體的業務場景下什么樣的查詢動作才是代價最小的執行方式,這就是優化器的核心工作。

CBO主要工作原理是通過代價模型(Cost Model)和統計信息估算每種執行方式的代價,然后選擇一種執行代價最優的執行方式。這里面代價模型是核心算法邏輯,統計信息是cost計算的數據源,二者配合完成cost計算;如果統計信息缺失,計算時代價模型會使用默認值來計算cost,當然這時cost會跟真實值存在較大偏差,大概率會出現選擇非最優執行計划的情況,因此統計信息是CBO模型中 cost計算的數據輸入,是CBO最核心的科技之一。

2 WHAT:都有哪些統計信息

統計信息是指數據庫描述表或者索引數據特征的信息,常見的有表記錄條數、頁面數等描述表規模的信息,以及描述數據分布特征的MCV(高頻非NULL值)、HISTOGRAM(直方圖)、CORRELATION等信息。

本文中通過如下用例來展示統計信息是如何表現表的數據特征的

DROP TABLE public.test;
CREATE TABLE public.test(a int, b int, c int[]);
INSERT INTO public.test VALUES (generate_series(1, 20), generate_series(1, 1200));
INSERT INTO public.test VALUES (generate_series(1, 1200), generate_series(1, 1200));
UPDATE public.test SET c = ('{' || a || ','|| a || '}')::int[] WHERE b <= 1000;
UPDATE public.test SET c = ('{' || a || ','|| b || '}')::int[] WHERE b > 1000;
ANALYZE public.test;

3 WHERE:統計信息在哪里

3.1 表規模信息

系統表pg_class中的reltuples和relpages兩個字段能夠反映表規模信息信息,其中relpages記錄了表數據存儲到幾個page頁里面,主要用於表從存儲接口掃描數據的代價計算;reltuples記錄了表記錄條數,主要用於掃描結果集行數估算。

查詢pg_class中的表規模估算信息,顯示表為2400行

單表全量數據查詢,通過explain查看表規模估算,顯示表掃描輸出行數估算為2400。

3.2 單列統計信息

單列統計信息是指表的單列的數據特征信息,存儲在系統表pg_statistic中。因為pg_statistic會存儲一些關鍵采樣值來描述數據特征,因此pg_statistic數據是敏感的,只有超級用戶才可以訪問pg_statistic。通常我們推薦用戶使用查詢系統視圖pg_stats來查詢當前用戶有查詢權限的表的統計信息,同時pg_stats信息的可讀性更強,pg_stats字段信息如下

查詢表public.test的a列的數據特征信息如下

通過統計新可以看出public.test的a列的NULL值比例為0,存在120個distinct值, 1~20是MCV值,每個出現的概率是0.0254167;21~1200出現在在直方圖統計信息中;

以查詢語句“SELECT count(1) FROM public.test WHERE a < 44;”為例說明統計信息在優化過程中行數估算場景下的作用

a) 所有MCV值均滿足a < 44,所有MCV值的比例為0.0254167 * 20 = 0.5083340

b) 44為直方圖中第三個邊界,直方圖中滿足a < 44的值的比例為(1-0.5083340)/100 *(3-1)= .0098333200

那么表中滿足a<56的tuples的個數為1243.6015680 ≈1244,通過explain打印執行計划如下

3.3 擴展統計信息

擴展統計信息存儲在系統表pg_statistic_ext里面,當前只支持多列統計信息這一種擴展統計信息類型。pg_statistic_ext會存儲一些關鍵采樣值來描述數據特征,因此pg_statistic_ext數據是敏感的,只有超級用戶才可以訪問pg_statistic_ext,通常我們推薦用戶使用查詢系統視圖pg_ext_stats來查詢當前用戶有查詢權限的擴展統計信息。

表的多個列有相關性且查詢中有同時基於這些列的過濾條件、關聯條件或者分組操作的時候,可嘗試收集多列統計信息。擴展統計信息需要手動進行收集(具體收集方法,下個小節會介紹),如下為test表(a,b)兩列的統計信息

4 HOW:如何生成統計信息

4.1 顯式收集統計信息

4.1.1 單列統計信息

通過如下命令收集單列統計信息:

{ ANALYZE | ANALYSE } [ VERBOSE ]  [ table_name [ ( column_name [, ...] ) ] ];

如語法描述,我們支持對指定列做統計信息,但是實際上我們很難統計實際業務SQL中到底使用了當前哪些表的列進行了代價估算,因此建議通常情況下對全表收集統計信息。

4.1.2 擴展統計信息

通過如下命令收集多列統計信息:

{ANALYZE | ANALYSE} [ VERBOSE ] table_name (( column_1_name, column_2_name [, ...] ));

需要注意的是,當前只支持在百分比采樣模式下生成擴展統計信息,因此在收集擴展統計信息之前請確保GUC參數default_statistics_target為負數

4.2 提升統計信息質量

analyze是按照隨機采樣算法從表上采樣,根據樣本計算表數據特征。采樣數可以通過配置參數default_statistics_target進行控制,default_statistics_target取值范圍為-100~10000,默認值為100。

1) 當default_statistics_target > 0時;采樣的樣本數為300*default_statistics_target,default_statistics_target取值越大,采樣的樣本也越大,樣本占用的內存空間也越大,統計信息計算耗時也越長

2) 當default_statistics_target < 0時,采樣的樣本數為 (default_statistics_target)/100*表的總行數,default_statistics_target取值越小,采樣的樣本也越大。但是default_statistics_target < 0時會把采樣數據下盤,不存在樣本占用的內存空間的問題,但是因為樣本過大,計算耗時長的問題同樣存在

default_statistics_target < 0時,實際采樣數是(default_statistics_target)/100*表的總行,所以我們又稱之為百分比采樣。

4.3 自動收集統計信息

當配置參數autoanalyze打開時,查詢語句走到優化器發現表不存在統計信息,會自動觸發統計信息收集,以滿足優化器的需求。以文檔的case為列

注:只有對統計信息敏感的復雜查詢動作(多表關聯等操作)的SQL語句執行時才會觸發自動收集統計信息;簡單查詢(比如單點,單表聚合等) 不會觸發自動收集統計信息

5 WHEN:什么時候收集統計信息

5.1 大規模數據變化

大規模數據導入/UPDATE/DELETE等操作,會導致表數據行數變化,新增的大量數據也會導致數據特征發生大的變化,此時需要對表重新收集統計信息

5.2 查詢新增數據

常見於業務表新增數據查詢場景,這個也是收集業務中最常見、最隱蔽的統計信息沒有及時更新的問題,這種場景最主要的特征如下

1) 存在一個按照時間增長的業務表

2) 業務表每天入庫新一天的數據

3) 數據入庫之后查詢新增數據進行數據加工分析

在最后步驟的數據加工分析時,最長的方法就是使用Filter條件從分區表中篩選數據,如passtime > ‘2020-01-19 00:00:00’ AND pastime < ‘2020-01-20 00:00:00’,假如新增數據入庫之后沒有做analyze,優化器發現Filter條件中的passtime取值范圍超過了統計信息中記錄的passtime值的上邊界,會把估算滿足passtime > ‘2020-01-19 00:00:00’ AND pastime < ‘2020-01-20 00:00:00’的tuple個數為1條,導致估算行數驗證失真

6 WHO:誰來收集統計信息

AP場景下業務表數據量一般都很大,單次導入的數據量也比較大,而且經常是數據導入即用,因此建議在業務開發過程中,根據數據變化量和查詢特征在需要的地方主動對相關表做analyze。

本文分享自華為雲社區《GaussDB(DWS)性能調優系列基礎篇一:萬物之始analyze統計信息》,原文作者:譡里個檔。

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM