database - 在字符串数组(带有 GIN 索引)与拆分行(B-Tree 索引)之间进行选择
问题描述
我有一个存储一列的数据库receiver
,以表示与数据相关的帐户(例如“查理”)。然而,这导致了大量的数据重复,因为一组数据可能会创建 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 亿行以下。
哪个选项更有效?
解决方案
您不应该使用数组,而应该使用规范化的数据模型,其中event
和receiver
是两个不同的表。表之间的关系应该通过外键约束来实现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 */;
推荐阅读
- javascript - if 语句测试为假,但由于 const 未通过而应该为真?
- mysql - 在查询结果中多次返回同一记录
- python-2.7 - Python 2.7 mmap http 运行后问题:TypeError:read() 恰好采用 1 个参数(给定 0)
- python - Python:如何计算当前时间和特定时间之间的持续时间?
- git - Git:从特定提交中合并特定文件
- json - 如何在没有[]的情况下从json中获取ID?
- python-asyncio - Python 异步输入
- python - 将具有多个值的列表转换为字典
- r - 拆分列,将结果列转换为因子
- java - Java 中的实体和模型应该使用 Primitive 还是 Object?