從Oracle索引的Clustering Factor看PG的Correlation
十多年前我為某企業的集采招標組織了一次PC SERVER的基準測試,參測的包括IBM、HP、華為、曙光、浪潮等。實際上我們對各廠商提出的配置要求是一致的,使用的CPU,磁盤,內存都差不多。雖然各個廠商調教產品的水平不同會導致一些差異。因此對于大多數性能測試用例來說測試成績應該差不多,在功耗和耐力測試上才能看出差距來。不過實際測試時,IBM在性能測試上的分數就比其他廠商高出很多。
這讓我十分疑惑,檢查了多次也沒有發現IBM有作弊的情況。我們的檢查工具會對數據做嚴格的檢查,一旦出現篡改測試數據等情況肯定是能發現的。就在我百思不得其解的時候,我看到IBM的測試區的桌上放著一本我寫的《ORACLE 優化日記》,其中書簽頁放在Clustering Factor相關的案例上。于是我眼前一亮,讓同事對幾張大表中的數據順序做了檢查。其中兩張在測試中大量做范圍掃描的表確實被他們重新做了排序。我們以前的檢查工具只檢查是否有數據被刪除,并沒有檢查數據的順序,因此就沒有發現這個作弊的行為。說實在的前些年做基準測試,IBM的測試團隊的技術水平還是很高的,他們總是能夠在不違反測試規則的情況下找到測試用例的漏洞。他們靠的是自身的優化能力來利用測試漏洞,這比某些靠野蠻作弊的廠商要高出不少。
我介紹的這個例子中有個概念索引的“Clustering Factor”,集簇因子。什么是集群因子(Clustering Factor)呢?集群因子反映的是如果通過一個索引范圍掃描一張表,需要訪問的表數據塊的數量。集群因子的計算方法如下:
(1) 掃描一個索引;
(2) 比較某行的ROWID和前一行的ROWID,如果這兩個ROWID不屬于同一個數據塊,那么集群因子增加1;
(3) 整個索引掃描完畢后,就得到了該索引的集群因子。
從上面集簇因子的計算方式我們可以看出,集簇因子反映了索引范圍掃描可能帶來的對整個表訪問過程的開銷情況,特別是IO開銷。實際上哪怕所有的塊都在DB CACHE里,如果這些行存在于少數數據塊中,掃描操作依然可以因為更少的閂鎖訪問而變得更快。
如果集簇因子接近于表存儲的塊數,說明這張表是按照索引字段的順序存儲的。如果集群因子接近于行的數量,那說明這張表不是按索引字段順序存儲的。在計算索引掃描的訪問成本時,集群因子十分有用。集群因子乘以選擇性參數就是訪問索引的開銷。如果這個統計數據不能反映出索引的真實情況,那么可能會造成優化器錯誤選擇執行計劃,全表掃描、索引范圍掃描還是快速索引掃描。另外,如果某張表上的大多數訪問是按照某個索引做索引掃描,那么將該表的數據按照索引字段的順序重新組織,可以提高該表的訪問性能。
PostgreSQL數據庫的索引沒有Oracle Clustering Factor的概念,那么PostgreSQL是根據什么來判斷索引掃描的效率的呢?在pg_stats視圖里,有一個字段:correlation(列數據相關性)。PostgreSQL在做表的Analyze的時候,也會分析字段的順序,通過correlation來告知DBA某個字段的物理存儲順序和邏輯順序之間的相關性是多少。
列的相關性是介于 -1 和 1 之間的值,代表了這個字段邏輯順序和物理順序之間的匹配程度。如果相關性為 1,則表中數據行的物理存儲是按升序存儲在表文件中的;如果為 -1,則按降序存儲。越接近-1或者+1,說明數據越有序。值為 0 表示物理順序和邏輯順序之間沒有聯系。
大家通過Oracle 的CF和PG的Correlation在算法上的差異可以看出,Oracle的CF能夠更為精準地反映出索引掃描的效率,PG有Correlation,也可以部分解決問題。下面我們通過一個例子來進一步說明。
圖片
我們來做個試驗,首先創建兩張測試表,都是從一個統一的基表數據來創建,只不過一個是按照ID排序的,一個是隨機選取的。
圖片
我們來看看這兩張表的ID字段的correlation,查看pg_stats之前一定要做一次analyze,否則是看不到數據的。
圖片
接下來我們對這兩張表做一次范圍掃描,看看效率有何不同。如上圖,我們看到按照ID排序的表的訪問效率要高不少。對于實際生產環境,如果數據塊不在內存里,這個差異還會放大,因為IO的成本更高。
從上面的案例我們可以學到些什么呢?首先我們可以學到一個優化的小技巧。對于經常會使用范圍掃描來訪問數據的表,如果大多數范圍掃描都是基于某個索引,那么將表數據針對索引順序進行重新排序,會大大提升掃描的效率。十多年前我們經常使用這個方法來優化用戶的系統。如果表的數據變化不是特別大,那么這種優化一年做一次就可以管用好久,如果是分區表的話,只需要對部分分區做就行了。這個方法對于絕大多數HEAP結構存儲數據的數據庫是有效的,對于B+樹或者LSM-TREE存儲結構的數據庫沒什么用處。因此對于Oracle、PG,這個小技巧是有用的。
對于PostgreSQL的用戶和DBA來說,我們也可以學會通過Correlation字段去分析某個字段的數據關聯性,從而分析一些范圍掃描的性能問題。
對于國產數據庫廠商來說,我想Oracle的Clustering Factor肯定比PG的Correlation更加精準,如果在做索引分析的時候,采集類似Oracle 集簇因子的屬性,對于CBO生成更為精準的執行計劃是有益的。
今天就寫這么多,希望我今天介紹的這個小知識點,能夠對大家有所幫助,有所啟發。