我应该花时间将列类型从CHAR(36)更改为UUID吗?


14

我的数据库中已经有几百万行。设计架构时,我不了解PostgreSQL UUID数据类型。

其中一张表具有1600万行(每个分片约350万至400万条记录),每天增长约50万条记录。如果需要,我仍然可以将生产系统停机几个小时。我将在一两个星期内没有这种奢侈。

我的问题是,这样做值得吗?我想知道JOIN的性能,磁盘空间的使用(完全gzip的转储为1.25 GiB),这种性质的事情。

表架构为:

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)

Answers:


13

我会考虑更改为UUID类型。 char(36)需要40个字节,uuid占用16因此您将每行节省24个字节,相当于每天12 MB,一年后为4 GB。加上索引。取决于您所拥有的硬件,虽然不多,但是可以。如果您有更多这样的改进机会,那就加起来了。

另外,我认为您的架构中没有任何约束可以确保 interaction_id格式正确。使用正确的类型也会为您提供帮助。

但是,如果您喜欢这样做,则比使用bigint会节省更多的钱,并且会获得更好的性能。您的应用程序非常大,以至于bigintID列的a不太可能工作。


我有一个分布式系统:多个数据源为交互生成ID,因此除非我为节点ID保留N位,否则我不能使用普通的BIGINT。
弗朗索瓦·博索莱尔

3
@FrançoisBeausoleil,为节点ID保留N位等于使用序列中的每N个数字(因此易于实现)。另外,您可能会考虑使用组合键。
不合理

1
协调多个序列(带有节点ID)在实践中是一个管理难题,容易出现人为错误。我认为没有理由在这种情况下不使用UUID,尤其是由于当今比特(存储和存储)都很便宜。的确,这种情况正是数十年前发明UUID的原因:在分布式系统之间共享数据而无需集中协调
罗勒·布尔克

6

我绝不是一个想做Postgres的人,但是根据我对SQL Server的了解,可以在数据页面上容纳的行越多,性能就越好(通常从磁盘读取数据最昂贵的操作)。因此,从36 ish 1字节宽的字段变为16字节GUID似乎可以直接节省成本。您可以产生的读取次数越少,返回结果的速度就越快。所有这些当然都假定GUID / UUID满足表的业务需求。如果UUID满足要求,会产生bigint吗?这样可以进一步节省每行另外8个字节的存储空间。

编辑1

对于Postgres中的字符数据,它们会产生额外的存储成本。少于127个字节的短字符串有1个字节的开销,而其他任何东西都有4个字节,这就是第二个响应者如何为36个字节的字段付出40字节的开销。但是,还有一个字符串压缩选项,因此也许不会花费全部40字节的费用。我无法说出最终费用是多少,但基本原理仍然存在:超过16字节的任何内容都会增加存储成本,读取所需的时间更长并消耗更多的内存。

短字符串(最多126个字节)的存储要求是1个字节加上实际的字符串,其中包括在字符情况下的空格填充。较长的字符串的开销为4个字节,而不是1个字节。较长的字符串由系统自动压缩,因此对磁盘的物理需求可能会更少。


3

除了空间问题之外,请记住,您需要更改每个表以使用正确的数据类型,否则联接性能将严重下降。


那是给定的,但感谢您提醒我。
弗朗索瓦·博索莱尔

3
当进行这样的重大更改时,我发现将所有内容写下来(无论要记住的内容多么简单)通常都会奏效。
mrdenny

3

除了节省数据和索引的大小(正如其他人所说的那样),这确实可以节省I / O成本,您还需要考虑的事情是如何为它生成新值,interaction_id以及对它的影响。索引和查询条件(联接)。

对于索引-会更小,但是,如果您的许多查询都使用索引扫描,则切换到UUID可能使索引扫描无法进行(取决于生成UUID的方式),并且bigint可能是更好的选择。

最后,由于实际的性能影响还取决于您的使用模式数据分布,因此您应该运行测试,并拥有一个可以在其中测试更改的开发和测试环境。

这将为您提供对性能影响的更准确的答案。


感谢您的
宝贵

我的访问模式是通过日期范围,使用screen_name或通过UUID加入。预计不会对唯一ID进行范围扫描。感谢您的回答,非常有用。
弗朗索瓦·博索莱尔
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.