Mysql

MySQL 和 PostgreSQL 中的聚集索引性能考慮

  • August 21, 2017

在 MySQL/InnoDB 中,聚集索引是主鍵的同義詞,因此選擇一個較差的主鍵會影響您的數據庫性能,即使用 UUID 作為 PK 是數據庫寫入的性能殺手。

現在,在 PostgreSQL 中,沒有像 MySQL 中那樣的集群限制。如果我選擇 UUID 作為 PK 有什麼影響?數據庫寫入性能殺手是否也像 MySQL 一樣存在於 PostgreSQL 中?

MySQL

雖然MySQL 文件字面意思是Typically, the clustered index is synonymous with the primary key,但它們並不是一回事。請記住,聚集索引(稱為 gen_clust_index)的創建方式是 PRIMARY KEY 的索引頁和表的行數據共存於同一頁中。擁有寬的 PRIMARY KEY 值,例如 UUID,會使 BTREE 頁面更寬。它甚至可能導致數據頁分裂。由於 MySQL 中的預設innodb_page_size為 16KB(這是MySQL 5.5 及更高版本中的固定編譯值),因此您必須期望數據頁面的行數更少,每 16KB 頁面的 PRIMARY KEY 導航空間也更小。

我之前已經討論過PRIMARY KEY影響:請參閱我的文章InnoDB 主鍵效率

PostgreSQL

Peter Eisentraut的StackOverflow 文章說The maximum length for a value in a B-tree index, which includes primary keys, is one third of the size of a buffer page, by default floor(8192/3) = 2730 bytes.

根據PostgreSQL 維基

通過將預設塊大小增加到 32k,最大表大小、行大小和最大列數可以增加四倍。最大表大小也可以使用表分區來增加。

由此,假設您使用 32K 塊而不是預設的 8K。您可以容納 4 倍的資訊,但仍然存在某種限制。

幸運的是,UUID 只有 16 個字節。我不希望它有驚天動地的缺點。

分析

InnoDB 對聚集索引的使用(儘管順序可能不靈活)將受益於較小的鍵,並且由於不必在聚集索引內管理盡可能多的空間來分配鍵,因此將有助於快速寫入。

雖然 PostgreSQL 的儲存引擎不像 MySQL 的 InnoDB 那樣受到限製或束縛,但較小的鍵肯定必須更快地處理並消耗更少的空間。這將提高 PostgreSQL、MySQL 或任何其他 RDBMS 的讀寫性能。

為了展示結構更改如何產生影響,讓我們使用 MySQL 的其他儲存引擎 MyISAM(它是非事務性的並且沒有聚集索引)。我曾經拿過一張 MyISAM 表,並將其行格式從動態更改為固定長度,並且在不涉及其他任何內容的情況下,性能提高了 20%。我使數據更大以獲得更好的讀取性能。寫入性能也有所提高,因為觸發任何空間管理的機制更少(請參閱我的文章What is the performance impact of using CHAR vs VARCHAR on a fixed-size field?)。

只需閱讀MySQL 文件,Optimizing Data Size您就會得到類似的片語

較小的表通常需要較少的主記憶體,而它們的內容在查詢執行期間被主動處理。

表數據的任何空間減少也會導致可以更快處理的更小的索引。

盡可能使用最有效(最小)的數據類型。MySQL 有許多專門的類型可以節省磁碟空間和記憶體。例如,盡可能使用較小的整數類型來獲得較小的表。MEDIUMINT 通常是比 INT 更好的選擇,因為 MEDIUMINT 列使用的空間減少了 25%。

為了進一步說明我對較小數據類型的觀點,我提到了 MySQL 的SELECT … PROCEDURE ANALYSE(); . 當您執行SELECT * FROM tablename PROCEDURE ANALYSE();時,輸出是對您的數據、最小值、最大值、平均值、值的 STD 以及(這裡是重點)每列的推薦數據類型的分析。

如果您應用ALTER TABLE命令來應用推薦的數據類型,則表最終必須變小。

甚至 PostgreSQL 也必須從較小的數據類型中受益。如何 ?

請回想一下 PostgreSQL 有一種稱為TOAST (The Outside Attribute Storage Technique) 的機制,我之前討論過(參見我的文章Proposal: MySQL blob handling revisionIt) has to juggle row data if there are large columns. 顯然,這種機制永遠不會被觸發是所有行都很小,而且很多行都可以舒適地放入 PostgreSQL 的 8K 塊中。

結論

由於您的問題似乎更側重於 PostgreSQL,所以讓我這樣回答您的問題:

如果我選擇 UUID 作為 PK 有什麼影響?數據庫寫入性能殺手是否也像 MySQL 一樣存在於 PostgreSQL 中?

PostgreSQL 將使用較小的列值更快地處理寫入。UUID 為 16 個字節。使用 8 字節整數作為 PRIMARY KEY 會比 UUID 更快地寫入和處理。一個 4 字節的整數甚至比這更快。這一切的教訓?PRIMARY KEY如果沒有必要,不要用更廣泛的價值觀放慢自己的腳步。

如果 UUID 不是順序變體,那麼按照它們創建的順序插入它們將導致索引中的一些隨機葉節點因插入的每一行而被弄髒。一旦索引足夠大,這將降低旋轉硬碟驅動器的寫入性能,因為它將無法整合寫入以高效寫入磁碟。

引用自:https://dba.stackexchange.com/questions/89185