PostgreSQL physical storage 和 inter db 值得閱讀
數據在物理介質上存儲是以page的形式,大小為8K,如下:
- a
tuple
或anitem
是行的同義詞 - a
relation
是表的同義詞 - a
filenode
是表示對表或索引的引用的id。 - a
block
和page
是等於它們代表存儲表的文件的8kb段信息。
PostgreSQL會把table數據和index以page的形式存儲在緩存中,同時在某些情況下(使用 prepared)也會把查詢計划緩存下來,但是不會去緩存具體的查詢結果。它是把查詢到的數據頁緩存起來,這個頁會包含連續的數據,即不僅僅是你所要的查詢的數據。
緩存指的是共享緩存,shared_buffers,所代表的內存區域可以看成是一個以8KB的block為單位的數組,即最小的分配單位是8KB。當Postgres想要從disk獲取(主要是table和index)數據(page)時,他會(根據page的元數據)先搜索shared_buffers,確認該page是否在shared_buffers中,如果存在,則直接命中,返回緩存的數據以避免I/O。如果不存在,Postgres才會通過I/O訪問disk獲取數據。
緩沖區的分配
我們知道Postgres是基於進程工作的系統,即對於每一個服務器的connection,Postgres主進程都會向操作系統fork一個新的子進程(backend)去提供服務。同時,Postgres本身除了主進程之外也會起一些輔助的進程。
因此,對於每一個connection的數據請求,對應的后端進程(backend)都會首先向LRU cache中請求數據頁page(這個數據請求不一定指的是SQL直接查詢的表或者視圖的page,比如index和系統表),這個時候就發起了一次緩沖區的分配請求。那么,這個時候我們就要抉擇了。如果要請求的block就在cache中,那最好,我們"pinned"這個block,並且返回cache中的數據。所謂的"pinned"指的是增加這個block的"usage count"。
當"usage count"為0時,我們就認為這個block沒用了,在后面cache滿的時候,它就該挪挪窩了。
那也就是說,只有當buffers/slots已滿的情況下,才會引發緩存區的換出操作。
緩存區的換出
決定哪個page該從內存中換出並寫回到disk中,這是一個經典的計算機科學的問題。
一個最簡單的LRU算法在實際情況下基本上很難work起來。因為LRU是要把最近最少使用的page換出去,但是我們沒有記錄上次運行時的狀態。
因此,作為一個折中和替代,我們追蹤並記錄每個page的"usage count",在有需要時,將那些"usage count"為0的page換出並寫回到disk中。后面也會提到,臟頁面也會被寫回disk。