索引:如果节点数相同,则整数vs字符串性能


26

我正在使用PostgreSQL(9.4)数据库在Ruby on Rails中开发应用程序。在我的用例中,表中的列将被非常频繁地查找,因为应用程序的重点是在模型上搜索非常特定的属性。

我目前正在决定是使用一种integer类型还是只使用典型的字符串类型(例如character varying(255)Rails中的默认字符串类型)作为列,因为我不确定索引的性能会有什么不同。

这些列是枚举。对于具有的可能值的数量,它们具有固定的大小。大多数枚举长度不超过5,这意味着该索引在应用程序的整个生命周期中或多或少是固定的;因此,整数和字符串索引的节点数将相同。

但是,将被索引的字符串可能长约20个字符,这在内存中大约是整数的5倍(如果整数是4个字节,并且字符串是每个字符1个字节的纯ASCII,则成立)。我不知道数据库引擎怎么做索引查找窗口,但如果它需要“扫描”的字符,直到它匹配准确,那么在本质上这意味着该字符串查找就超过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 | ... |

我希望这是有道理的。基本上,因为整数占用的空间较小,所以它的“匹配”速度比字符串对应的速度更快。也许这是一个完全错误的猜测,但是我不是专家,所以这就是为什么我问你们!我想我刚刚找到的答案似乎支持我的假设,但我想确定。

列中可能使用的任何一个值都不会改变,因此索引本身也不会改变(除非我向枚举添加了新值)。在这种情况下,使用integer或会不会产生性能差异varchar(255),或者使用整数类型是否更有意义?


我问的原因是Rails的enum类型将整数映射到字符串键,但它们并不意味着是面向用户的列。本质上,您无法验证枚举值是有效值,因为无效值会ArgumentError在运行任何验证之前引起一个。使用string类型可以进行验证,但是如果有性能损失,我宁愿绕开验证问题。

Answers:


32

简短的回答:integer是快于varchartext在每一个方面。对于小桌子和/或短键并没有多大关系。差异随着键的长度和行数而增加。

字符串... 20个字符长,在内存中大约是整数的5倍(如果整数是4个字节,并且字符串是每个字符1个字节的纯ASCII,则表示成立)

为了精确,字符类型(textvarchar)占据恰好21个用于在磁盘上的20个ASCII字符和字节23个在RAM字节。详细评估:

同样重要的是:COLLATION规则可能会使字符数据的排序更加昂贵-与数字数据类型不同:

在大多数情况下,索引大小可能是导致性能差异最大的原因。考虑每个索引元组的开销(基本上与表相同):4个字节用于项目指针,而24个字节用于元组头。所以索引元组integer将达到36个字节(包括4个字节的对齐填充)和varchar(20)与20个ASCII字符将是52个字节(也含填充)。细节:

除了所有理论之外,最好只是测试一下:

Postgres 9.5引入了一种对长字符串数据(关键字“缩写关键字”)进行排序的优化方法。但是Linux上某些C库函数中的错误迫使该项目对Postgres 9.5.2中的非C归类禁用该功能。发行说明中的​​详细信息。

但是,如果您实际上使用的是Postgres enum类型,则这些考虑中的大多数都是不相关的,因为integer无论如何,这些考虑都是在内部用值实现的。手册:

一个enum值在磁盘上占用四个字节。

撇开:varchar(255)过去对于SQL Server的早期版本有意义,它可以在内部使用更有效的数据类型,最多255个字符。但是255个字符的奇数长度限制对Postgres的性能完全没有特殊影响。


1
对于varchar(255)vs. ,SQL Server中没有隐藏的优化varchar(260)。SQL Server 6.x可能存在这种情况,但很长一段时间以来并非如此。
a_horse_with_no_name 2016年

@a_horse_with_no_name:谢谢,我作了相应澄清。
Erwin Brandstetter,

抱歉,花了这么长时间接受了我,我对该项目的开发一直很慢;)
Chris Cirefice

这个答案对Postgres 10仍然有效吗?
马蒂

1
@Matty:仍然有效。而且,第11页也没有任何变化。
Erwin Brandstetter
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.