Home 科技 PostgreSQL 的哈...

PostgreSQL 的哈希索引現在很酷


由於我剛剛提交了最後一個改進PostgreSQL 11 哈希索引的補丁,並且大部分哈希索引的改進都致力於預計下週發布的PostgreSQL 10(LCTT 譯註:已發布),因此現在似乎是對過去18 個月左右所做的工作進行簡要回顧的好時機。在版本10 之前,哈希索引在並發性能方面表現不佳,缺少預寫日誌記錄,因此在宕機或複制時都是不安全的,並且還有其他二等公民。在PostgreSQL 10 中,這在很大程度上被修復了。

雖然我參與了一些設計,但改進哈希索引的首要功勞來自我的同事Amit Kapila, 他在這個話題下的博客值得一讀 。哈希索引的問題不僅在於沒有人打算寫預寫日誌記錄的代碼,還在於代碼沒有以某種方式進行結構化,使其可以添加實際上正常工作的預寫日誌記錄。要拆分一個桶,系統將鎖定已有的桶(使用一種十分低效的鎖定機制),將半個元組移動到新的桶中,壓縮已有的桶,然後鬆開鎖。即使記錄了個別更改,在錯誤的時刻發生崩潰也會使索引處於損壞狀態。因此,Aimt 首先做的是重新設計鎖定機制。 新的機制在某種程度上允許掃描和拆分並行進行,並且允許稍後完成那些因報錯或崩潰而被中斷的拆分。完成了一系列漏洞的修復和一些重構工作,Aimt就打了另一個補丁, 添加了支持哈希索引的預寫日誌記錄

與此同時,我們發現哈希索引已經錯過了許多已應用於B 樹索引多年的相當明顯的性能改進。因為哈希索引不支持預寫日誌記錄,以及舊的鎖定機制十分笨重,所以沒有太多的動機去提升其他的性能。而這意味著如果哈希索引會成為一個非常有用的技術,那麼需要做的事只是添加預寫日誌記錄而已。 PostgreSQL 索引存取方法的抽象層允許索引保留有關其信息的後端專用緩存,避免了重複查詢索引本身來獲取相關的元數據。 B樹和SQLite的索引正在使用這種機制,但哈希索引沒有,所以我的同事Mithun Cy寫了一個補丁來使用此機制緩存哈希索引的元頁 。同樣,B 樹索引有一個稱為“單頁回收”的優化,它巧妙地從索引頁移除沒用的索引指針,從而防止了大量索引膨脹。我的同事Ashutosh Sharma打了一個補丁將這個邏輯移植到哈希索引上 ,也大大減少了索引的膨脹。最後,B樹索引自2006年以來就有了一個功能,可以避免重複鎖定和解鎖同一個索引頁——所有元組都在頁中一次性刪除,然後一次返回一個。 Ashutosh Sharma也將此邏輯移植到了哈希索引中 ,但是由於缺少時間,這個優化沒有在版本10中完成。在這個博客提到的所有內容中,這是唯一一個直到版本11 才會出現的改進。

關於哈希索引的工作有一個更有趣的地方是,很難確定行為是否真的正確。鎖定行為的更改只可能在繁重的並發狀態下失敗,而預寫日誌記錄中的錯誤可能僅在崩潰恢復的情況下顯示出來。除此之外,在每種情況下,問題可能是微妙的。沒有東西崩潰還不夠;它們還必須在所有情況下產生正確的答案,並且這似乎很難去驗證。為了協助這項工作,我的同事Kuntal Ghosh 先後跟進了最初由Heikki Linnakangas 和Michael Paquier 開始的工作,並且製作了一個WAL 一致性檢查器,它不僅可以作為開發人員測試的專用補丁,還能真正提交到PostgreSQL 。在提交之前,我們對哈希索引的預寫日誌代碼使用此工具進行了廣泛的測試,並十分成功地查找到了一些漏洞。這個工具並不僅限於哈希索引,相反:它也可用於其他模塊的預寫日誌記錄代碼,包括堆,當今的所有AM 索引,以及一些以後開發的其他東西。事實上,它已經成功地在BRIN中找到了一個漏洞

雖然WAL 一致性檢查是主要的開發者工具——儘管它也適合用戶使用,如果懷疑有錯誤——也可以升級到專為數據庫管理人員提供的幾種工具。 Jesper Pedersen寫了一個補丁來升級pageinspect contrib模塊來支持哈希索引 ,Ashutosh Sharma做了進一步的工作,Peter Eisentraut提供了測試用例(這是一個很好的辦法,因為這些測試用例迅速失敗,引發了幾輪漏洞修復)。多虧了Ashutosh Sharma的工作,pgstattuple contrib模塊也支持哈希索引了

一路走來,也有一些其他性能的改進。我一開始沒有意識到的是,當一個哈希索引開始新一輪的桶拆分時,磁盤上的大小會突然加倍,這對於1MB 的索引來說並不是一個問題,但是如果你碰巧有一個64GB 的索引,那就有些不幸了。 Mithun Cy通過編寫一個補丁,把加倍過程分為四個階段在某個程度上解決了這一問題,這意味著我們將從64GB到80GB到96GB到112GB到128GB,而不是一次性從64GB到128GB 。這個問題可以進一步改進,但需要對磁盤格式進行更深入的重構,並且需要仔細考慮對查找性能的影響。

七月時,一份來自於“AP”測試人員的報告使我們感到需要做進一步的調整。 AP 發現,若試圖將20 億行數據插入到新創建的哈希索引中會導致錯誤。為了解決這個問題,Amit修改了拆分桶的代碼, 使得在每次拆分之後清理舊的桶 ,大大減少了溢出頁的累積。為了得以確保,Aimt和我也增加了四倍的位圖頁的最大數量 ,用於跟踪溢出頁分配。

雖然還是有更多的事情要做,但我覺得,我和我的同事們——以及在PostgreSQL 團隊中的其他人的幫助下——已經完成了我們的目標,使哈希索引成為一個一流的功能,而不是被嚴重忽視的半成品。不過,你或許會問,這個功能可能有哪些應用場景。我在文章開頭提到的(以及鏈接中的)Amit 的博客內容表明,即使是pgbench 的工作負載,哈希索引頁也可能在低級和高級並發方面優於B 樹。然而,從某種意義上說,這確實是最壞的情況。哈希索引的賣點之一是,索引存儲的是字段的哈希值,而不是原始值——所以,我希望像UUID 或者長字符串的寬鍵將有更大的改進。它們可能會在讀取繁重的工作負載時做得更好。我們沒有像優化讀取那種程度來優化寫入,但我鼓勵任何對此技術感興趣的人去嘗試並將結果發到郵件列表(或發私人電子郵件),因為對於開發一個功能而言,真正關鍵的並不是一些開發人員去思考在實驗室中會發生什麼,而是在實際中發生了什麼。

最後,我要感謝Jeff Janes 和Jesper Pedersen 為這個項目及其相關所做的寶貴的測試工作。這樣一個規模適當的項目並不易得,以及有一群堅持不懈的測試人員,他們勇於打破任何廢舊的東西的決心起了莫大的幫助。除了以上提到的人之外,其他人同樣在測試,審查以及各種各樣的日常幫助方面值得讚揚,其中包括Andreas Seltenreich,Dilip Kumar,Tushar Ahuja,Alvaro Herrera,Micheal Paquier,Mark Kirkwood,Tom Lane ,Kyotaro Horiguchi。謝謝你們,也同樣感謝那些本該被提及卻被我無意中忽略的所有朋友。

Ubuntu 16.04下安裝PostgreSQL和phpPgAdmin http://www.linuxidc.com/Linux/2016-08/134260.htm

Linux下RPM包方式安裝PostgreSQL http://www.linuxidc.com/Linux/2016-03/128906.htm

Linux下安裝PostgreSQL http://www.linuxidc.com/Linux/2016-12/138765.htm

Linux下PostgreSQL安裝部署指南http://www.linuxidc.com/Linux/2016-11/137603.htm

Linux下安裝PostgreSQL並設置基本參數http://www.linuxidc.com/Linux/2016-11/137324.htm

Ubuntu 16.04下PostgreSQL主從復製配置http://www.linuxidc.com/Linux/2017-08/146190.htm

Fedota 24將數據庫升級到PostgreSQL 9.5 http://www.linuxidc.com/Linux/2016-11/137374.htm

CentOS 7安裝配置PostgreSQL9.6 http://www.linuxidc.com/Linux/2017-10/147536.htm

CentOS5.8_x64下離線安裝PostgreSQL 9.1 http://www.linuxidc.com/Linux/2017-10/147822.htm

CentOS 6.5下PostgreSQL服務部署http://www.linuxidc.com/Linux/2017-01/139144.htm


via: https://rhaas.blogspot.jp/2017/09/postgresqls-hash-indexes-are-now-cool.html

作者: Robert Haas譯者: polebug校對: wxy

本文由[LCTT]( https://github.com/LCTT/TranslateProject)原創編譯,[Linux中國](https://linux.cn/)榮譽推出

本文永久更新鏈接地址http://www.linuxidc.com/Linux/2017-11/148619.htm

linux



文章來源