在字符串数组(具有GIN索引)和拆分行(B树索引)之间进行选择

时间:2019-02-02 12:10:58

标签: database postgresql database-design data-modeling

我有一个数据库,其中存储一列receiver,以表示该数据所涉及的帐户(例如“ Charlie”)。但是,这导致大量数据重复,因为一组数据可能会创建3个单独的行,唯一的区别是receiver列。

|---------------------|------------------||---------------------|------------------|
|      Receiver       |       Event      ||         Date        |     Location    |
|---------------------|------------------||---------------------|------------------|
|       Alpha         |         3        ||          12         |         USA       |
|---------------------|------------------||---------------------|------------------|
|       Bravo         |         3        ||          12         |         USA       |
|---------------------|------------------||---------------------|------------------|
|       Charlie       |         3        ||          12         |         USA       |
|---------------------|------------------||---------------------|------------------|

在重新设计数据库时,我考虑过使用带有GIN索引的数组,而不是接收器上当前的B-Tree索引。我建议的新表将如下所示:

|-------------------------------|------------------||------------------|-------------------|
|           Receivers           |       Event      ||      Date        |     Location      |
|-------------------------------|------------------||------------------|-------------------|
| ["Alpha", "Bravo", "Charlie"] |         3        ||       12         |         USA       |
|-------------------------------|------------------||------------------|-------------------|

当前所有查询中的95%的格式为:SELECT * FROM table WHERE Receiver = Alpha

此外,该表当前包含超过40亿行,这将使其减少到不足20亿行。

哪个选项更有效?

1 个答案:

答案 0 :(得分:0)

您不应该使用数组,而是使用规范化的数据模型,其中eventreceiver是两个不同的表。表之间的关系应通过receiver上的外键约束来实现。

表格如下:

CREATE TABLE occurrence (
   occurrence_id bigint PRIMARY KEY,
   event integer NOT NULL,
   date integer NOT NULL,
   location text NOT NULL
);

CREATE TABLE receiver (
   receiver_id bigint PRIMARY KEY,
   receiver_name text NOT NULL
);

CREATE TABLE log_entry (
   occurrence_id bigint NOT NULL REFERENCES occurrence,
   receiver_id   bigint NOT NULL REFERENCES receiver,
   PRIMARY KEY (occurrence_id, receiver_id)
);

日志条目引用事件发生和接收方。

您想查询

SELECT r.receiver_name,
       o.event,
       o.date,
       o.location
FROM occurrence AS o
   JOIN log_entry AS l USING (occurrence_id)
   JOIN receiver AS r USING (receiver_id)
WHERE /* your conditions */;