為什麼數據庫的預設頁面大小如此之小?
在 PostgreSQL 和 SQL Server 中,預設頁面大小為 8 KB,在 MySQL 中為 16 KB,在 IBM DB2 和 Oracle 中僅為 4 KB。
為什麼這些頁面尺寸這麼小?
是否有歷史或記憶體使用原因?
我正在執行 Linux(Fedora 34、64 位、兩個核心、四個 CPU、32 GB RAM - PostgreSQL 13.3)。
如果我執行
stat -f some_random_file
如下:[pol@fedora inst]$ stat -f blah.txt File: "blah.txt" ID: f1b798b1610e7067 Namelen: 255 Type: ext2/ext3 Block size: 4096 Fundamental block size: 4096 Blocks: Total: 322411548 Free: 316122834 Available: 299727775 Inodes: Total: 81960960 Free: 81739842 [pol@fedora inst]$
注意:
Block size: 4096
= 4096 字節 = 32768 位。現在,即使您有一個長度為兩個字節的文件
"Hi"
(作業系統將磁碟上的內容作為 4K“塊”取出,然後以 4K 塊的形式返回 - 請參閱此處以獲取快速概覽。您可能想在自己的系統上進行測試。磁碟本身有自己的“原子”單元。對於 HDD,這通常是 512 字節,但請參見上面的連結 - “在硬體級別,舊驅動器使用 512B 扇區,而新設備通常以更大的塊(通常為 4kB 甚至 8kB)寫入數據”。有關HDD,請參見此處,有關 SSD ,請參見此處。(感謝@RonJohn 的評論)。
同樣,數據庫將以塊的形式讀取和讀取數據(也稱為頁面 - 術語可能會令人困惑) - 如果您更改記錄中的一個單獨的位,數據庫仍然必須讀取記錄所在的整個頁面並寫入修改完成後將整個頁面放回磁碟。
在 PostgreSQL 上,您有 8K 的預設塊大小。
test_1=# SELECT name, setting, short_desc, extra_desc FROM pg_settings WHERE name like '%block%' or short_desc LIKE '%block%'; name | setting | short_desc | extra_desc ----------------+---------+----------------------------------------------+------------ block_size | 8192 | Shows the size of a disk block. | wal_block_size | 8192 | Shows the block size in the write ahead log. | (2 rows) test_1=#
重要的是 HDD、作業系統和 RDBMS“原子單元”大小之間沒有太大的差距 - 否則,您將面臨撕裂頁面的風險- 從連結:
避免破損的頁面
對於 Postgres 文件佈局,Postgres 一次將數據讀取和寫入磁碟 8kb。大多數作業系統使用較小的頁面大小,例如 4kb。如果 Postgres 在其中一個作業系統上執行,可能會出現一個有趣的邊緣情況。由於 Postgres 以 8kb 為單位寫入磁碟,而作業系統以 4kb 為單位寫入磁碟,因此如果電源在正確的時間斷電,則 Postgres 正在執行的 8kb 寫入可能只有 4kb 被寫入磁碟。這種邊緣情況有時被稱為“撕裂的頁面”。Postgres 確實有一種解決破損頁面的方法,但它確實增加了 Postgres 需要執行的 I/O 量。
另外,請參見此處:
部分寫入/撕裂頁面
那麼整頁寫的是什麼?正如 postgresql.conf 中的評論所說,這是一種從部分頁面寫入中恢復的方法——PostgreSQL 使用 8kB 頁面(預設情況下),但堆棧的其他部分使用不同的塊大小。Linux 文件系統通常使用 4kB 頁面(可以使用較小的頁面,但在 x86 上最大為 4kB),在硬體級別上,舊驅動器使用 512B 扇區,而新設備通常以更大的塊寫入數據(通常為 4kB 甚至 8kB) .
因此,當 PostgreSQL 寫入 8kB 頁面時,儲存堆棧的其他層可能會將其分成更小的塊,單獨管理。這提出了關於寫入原子性的問題。8kB 的 PostgreSQL 頁面可以分成兩個 4kB 的文件系統頁面,然後分成 512B 扇區。現在,如果伺服器崩潰(電源故障、核心錯誤……)怎麼辦?
與與電腦科學相關的許多事情一樣,這是一個權衡和妥協的問題 -這是 PostgreSQL 在相同系統上執行的基準,只是改變了塊大小 - 來自文章:
Samsung SSD 840, 500 GB TPS (txns/second) blocksize=2k 147.9 blocksize=4k 141.7 blocksize=8k 133.9 blocksize=16k 127.2 blocksize=1MB 42.5
因此,您可以看到一個天真的“使 db 塊大小盡可能大”的方法效果不佳。關於這一點我要說的是,數據庫基準測試完全是一個泥潭……對於某些應用程序來說,1 MB可能很合適——儘管超出 16 KB 需要相當大的理由。系統的預設參數就是 -預設值- 在最廣泛的情況下選擇得相當好……
關於。問題的歷史部分 - 是的,很多都與磁碟進入 512 字節扇區時的歷史有關…… HDD,儘管速度有所提高和鏽蝕成分的逐步改進,但自第一個 HDD 以來基本上沒有變化 - HDD 的性能已經遠遠落後於 CPU 和 RAM…容量增加了,但速度沒有那麼多(見這裡)——因此“NoSQL”潮流運動的誕生(但那是另一天的工作:-))!
這幾天,這個地區發生了很多事情……
如果你有興趣 - 並且有時間 - 我已經仔細閱讀了幾次,但它有點高於我的工資等級……這裡有一篇關於Linux I/O 的文章以及它是如何被 io_uring 徹底改變的(參見wiki - 以及其中的連結)。
英特爾還提供了一個開源工具包,即SPDK(儲存性能開發工具包),它似乎(至少在我未經訓練的人看來)是某種允許使用者空間程序直接訪問硬體而無需通過核心的方式。 .這是關於如何將其應用於數據庫的有趣觀點。
而且,同樣出現在現場的是(8)字節可定址儲存……由於硬體設計人員最熟悉的原因,SSD(至少其中一些)也有塊和頁面……它們不是靈丹妙藥(檢查出 TLC SSD 和普通 HDD 寫入速度 - 只有 30% 的增益)。
然而,在(遠?)地平線上,有持久記憶——來自文章:
8 字節原子性
持久性記憶體(例如英特爾傲騰 DC 持久性記憶體)本機按字節執行,而不是像傳統儲存那樣在數據塊中執行。數據在 Persistent Memory 中最多保留為 8 字節的塊(同樣,使用預設行為)。對於基於 BLOCK 結構的應用程序(如數據庫),持久記憶體的 8 字節原子性可能是一個問題。寫入 8,192 字節的數據(一個 8K 塊)將被持久化為 1,024 個 8 字節的塊。電源故障或其他異常情況可能會使數據塊“破碎”或“撕裂”成碎片,其中部分數據塊包含舊數據,而其他部分包含新數據。需要更改應用程序(例如數據庫)以容忍這種類型的塊破裂或撕裂。否則,這些是有效損壞的數據塊。
因此,我們可以看到這些系統仍然會出現諸如撕裂頁面之類的問題- 但它們確實提供了可能性 - 當數據庫程序員趕上時 - 塊大小 = 8 字節(而不是8 KB) - 您想要更改BIGINT 的值,你所要做的就是讀 8 個字節,寫 8 個字節…
也許如果我們降低到這個級別,或者甚至是單個字節的特異性,那麼對於磁碟、作業系統和 RDBMS,頁面的整個概念就會消失?我確信仍然會有文件系統——只是不確定它們將如何工作。
這是一個引人入勝的領域(問題+1!),尤其是對於數據庫極客。