Postgresql

索引:如果節點數相同,則整數與字元串的性能

  • May 3, 2020

我正在使用 PostgreSQL (9.4) 數據庫在 Ruby on Rails 中開發應用程序。對於我的案例,表中的列將被非常頻繁地查找,因為應用程序的重點是在模型上搜尋非常具體的屬性。

我目前正在決定是使用integer類型還是簡單地使用典型的字元串類型(例如character varying(255)這是 Rails 中的預設值)作為列,因為我不確定索引上的性能差異是什麼。

這些列是列舉。對於它們可以擁有的可能值的數量,它們具有固定的大小。大多數列舉長度不超過 5,這意味著索引在應用程序的整個生命週期中或多或少是固定的;因此,整數和字元串索引在節點數上是相同的。

但是,將被索引的字元串可能有大約 20 個字元長,在記憶體中大約是整數的 5 倍(如果整數是 4 個字節,並且字元串是純 ASCII,每個字元 1 個字節,那麼這成立)。我不知道數據庫引擎如何進行索引查找,但是如果它需要“掃描”字元串直到它完全匹配,那麼本質上這意味著字元串查找將比整數查找慢 5 倍;“掃描”直到匹配整數查找將是 4 個字節而不是 20 個字節。這就是我的想像:

查找值為(整數)4:

掃描…………………….. 找到 | 正在獲取記錄… |BYTE_1|BYTE_2|BYTE_3|BYTE_4|BYTE_5|BYTE_6|BYTE_7|BYTE_8|…|

查找值為(字元串)“some_val”(8 個字節):

掃描…………………………………………. ………………… 找到 | 正在獲取記錄… |BYTE_1|BYTE_2|BYTE_3|BYTE_4|BYTE_5|BYTE_6|BYTE_7|BYTE_8|…|

我希望這是有道理的。基本上,因為整數佔用的空間更少,它可以比其字元串對應物更快地“匹配”。也許這是一個完全錯誤的猜測,但我不是專家,所以我問你們!我想我剛剛找到的這個答案似乎支持我的假設,但我想確定一下。

列中可能值的數量在使用任何一個時都不會改變,因此索引本身不會改變(除非我向列舉添加了一個新值)。在這種情況下,使用or****會有性能差異,還是使用整數類型更有意義?integer``varchar(255)


我問的原因是 Rails 的enum類型將整數映射到字元串鍵,但它們並不意味著是面向使用者的列。本質上,您無法驗證列舉值是否有效,因為無效值會導致ArgumentError在執行任何驗證之前出現。使用string類型將允許驗證,但如果存在性能成本,我寧願繞過驗證問題。

簡短的回答:integervarchartext在各個方面都快。對於小桌子和/或短鍵來說並不重要。差異隨著鍵的長度和行數的增加而增加。

string … 20 個字元長,在記憶體中大約是整數的 5 倍(如果整數是 4 個字節,並且字元串是純 ASCII,每個字元 1 個字節,那麼這成立)

準確地說,對於磁碟上的 20 個 ASCII 字元和RAM 中的23text個字節,字元類型 (或varchar) 正好佔用**21個字節。**詳細評估:

同樣重要的是:COLLATION規則可以使字元數據的排序更加昂貴 - 與數字數據類型不同:

在大多數情況下,索引大小可能是造成性能差異的最大原因。考慮每個索引元組的成本(基本上與表相同):4 個字節用於項目標識符,8 個字節用於索引元組標頭。因此,索引元組為integer20個字節(包括 4 個字節的對齊填充),對於varchar(20)20 個 ASCII 字元,它將為36 個字節(也包括填充)。細節:

除了所有的理論:最好只測試:

Postgres 9.5引入了對長字元串數據(關鍵字**“縮寫鍵”**)進行排序的優化。但是 Linux 上的一些 C 庫函式中的一個錯誤迫使該項目在 Postgres 9.5.2 中禁用非 C 排序規則的功能。發行說明中的詳細資訊。

但是,如果您實際使用 Postgres**enum**類型,則這些注意事項中的大多數都是無關緊要的,因為integer無論如何這些都是在內部使用值實現的。手冊:

一個enum值佔用磁碟上的四個字節。

旁白:varchar(255)過去對早期版本的 SQL Server 有意義,它可以在內部使用更有效的數據類型,最多 255 個字元的限制。但是 255 個字元的奇數長度限制在 Postgres 中根本沒有特殊意義。

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