Linux中國

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。謝謝你們,也同樣感謝那些本該被提及卻被我無意中忽略的所有朋友。

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/)榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國