构建数据库结构的另一种方法

时间:2016-09-03 16:51:20

标签: database postgresql database-design architecture storage

我必须优化我的小数据库,因为它太慢了,也许我们会一起找到另一个解决方案。

首先让我们谈谈存储在数据库中的数据。有两个对象:users,让我们说messages

用户

有类似的东西:

 +----+---------+-------+-----+
 | id | user_id | login | etc |
 +----+---------+-------+-----+
 |  1 |  100001 |   A   | ....|
 |  2 |  100002 |   B   | ....|
 |  3 |  100003 |   C   | ....|
 |... |  ...... |  ...  | ....|
 +----+---------+-------+-----+

此表内没有问题。 (不要害怕iduser_iduser_id被其他应用程序使用,因此它必须在这里。)

消息

第二个表有一些问题。每个用户都有这样的消息:

 +----+---------+------+----+
 | id | user_id | from | to |
 +----+---------+------+----+
 |  1 |   1     | aab  | bbc|
 |  2 |   2     | vfd  | gfg|
 |  3 |   1     | aab  | bbc|
 |  4 |   1     | fge  | gfg|
 |  5 |   3     | aab  | gdf|
 |... |  ...... |  ... | ...|
 +----+---------+------+----+

不需要edit条消息,但应该有机会更新用户的消息列表。例如,外部服务将所有用户的消息发送到数据库,并且必须更新列表。 最重要的是,大约有30 Mio用户,普通用户有500多条消息。我必须搜索字段from并计算匹配数的另一个问题。我设计了一个带连接的简单SQL查询,但获取数据需要花费太多时间。

所以......它的数据量非常大。我决定不使用RDS(我使用Postgresql)并决定转移到Clickhouse等数据库。

但是我遇到了一个问题,例如Clickhouse不支持UPDATE语句。

要解决此问题,我决定将邮件存储为一行。因此表Messages应该是这样的:

                 Here I'd like to store messages in JSON format
                 {"from":"aaa", "to":bbe"}
                 {"from":"ret", "to":fdd"}
                 {"from":"gfd", "to":dgf"}
                    ||                        
                    \/
 +----+---------+----------+------+    And there I'd like to store the 
 | id | user_id | messages | hash | <= hash of the messages. 
 +----+---------+----------+------+   

我认为messages列中的全文搜索会节省一些时间资源等等。

你有什么想法吗? :)

2 个答案:

答案 0 :(得分:2)

在ClickHouse中,最佳方式是将数据存储在&#34;大平台&#34;中。 因此,您将每条消息存储在一个单独的行中。 即使在单个节点上,也可以为ClickHouse提供150亿行。

此外,让每个用户直接在消息表(预加入)中属性是合理的,因此您不需要进行JOIN。如果用户属性未更新,则适合。

这些属性将为每个用户提供重复的值。消息 - 它很好,因为ClickHouse可以很好地压缩数据,特别是重复的值。

如果用户&#39;属性更新,考虑将用户表存储在单独的数据库中并使用“外部词典”。加入它的功能。

如果消息已更新,请不要更新。将具有修改后的消息的另一行写入表中,并保留旧消息。

为您的桌子拥有正确的主键非常重要。您应该使用MergeTree系列中的表,该表不断按主键重新排序数据,因此可以保持范围查询的效率。主键不需要是唯一的,例如,如果您经常编写&#34; from = ...&#34;并且必须在短时间内处理这些查询,您可以将主键定义为(from)

您可以使用user_id作为主键:如果用户ID的查询频繁且必须尽可能快地处理,但随后在&#39;中使用谓词进行查询。将扫描整个表(请注意ClickHouse有效地进行全面扫描)。

如果您需要通过许多不同的属性快速查找,您可以只使用不同的主键复制表。通常情况下,该表格将被压缩得足够好,您可以为不同范围的查询提供具有不同顺序的少量副本数据。

答案 1 :(得分:0)

首先,当我们有这么大的数据集时,如果可能的话,fromto列应该是整数,因为它们的比较速度更快。

其次,您应该考虑创建适当的索引。由于每个用户的记录相对较少(500个与总共30M相比),因此它可以为您带来巨大的性能优势。

如果其他一切都失败了,请考虑使用分区:

https://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

在你的情况下,它们将是动态的,并且阻碍第一次插入非常大,所以我认为它们只是最后一次,如果非常有效,那么。