我们有一个规则的一般概念,其中特定的实现细节存储在他们自己的表中。我们目前有以下架构:
Rule
* id
* name
* ruleAId
* ruleBId
* ....
* ruleNId
* created
* updated
RuleA
* id
* ...
RuleB
* id
* ...
....
RuleC
* id
* ...
Run Code Online (Sandbox Code Playgroud)
我们不喜欢的部分是每个特定规则实现都有一个可为空的列。
我们有两种可能的解决方案,但都有明显的缺点:
将规则 ID 存储在具体的实现表上,所以我们的模式变成:
RuleA
* id
* ruleId
* ...
Rule
* id
* name
* created
* updated
Run Code Online (Sandbox Code Playgroud)
正如标题所暗示的那样,这意味着每次需要查找规则实现时都要进行 N 次查询。估计对性能不利。
如果我们从 Rule 表中删除对参照完整性的需求,我们只需要一个列来存储特定的实现主键和一个枚举来告诉我们 id 用于哪个表,给我们:
Rule
* id
* name
* implementationType
* implementationId
* created
* updated
RuleA
* id
...
Run Code Online (Sandbox Code Playgroud)
理想情况下,我们可以使用具有参照完整性的选项二。如果 implementationId 不是 bigInt,它可以是 FK 或 RuleA 或 RuleB 或 ... RuleN。
这可以在应用程序本身中进行编码,但数据库让我们保持诚实是很好的。
我们正朝着选项二前进,但是如果人们认为我错过了一个更惯用的 SQL 解决方案,我很感兴趣吗?
添加示例架构:
CREATE SEQUENCE s_rulea_id;
CREATE TABLE rulea (id BIGINT PRIMARY KEY default nextval('s_rulea_id'));
CREATE SEQUENCE s_ruleb_id;
CREATE TABLE ruleb (id BIGINT PRIMARY KEY default nextval('s_ruleb_id'));
CREATE SEQUENCE s_rulec_id;
CREATE TABLE rulec (id BIGINT PRIMARY KEY default nextval('s_rulec_id'));
CREATE SEQUENCE s_rulen_id;
CREATE TABLE rulen (id BIGINT PRIMARY KEY default nextval('s_rulen_id'));
CREATE SEQUENCE s_rule_id;
CREATE TABLE rule (id BIGINT PRIMARY KEY default nextval('s_rule_id'),
name CHARACTER VARYING(128) NOT NULL,
ruleAid BIGINT DEFAULT NULL references rulea(id),
ruleBid BIGINT DEFAULT NULL references ruleb(id),
ruleCid BIGINT DEFAULT NULL references rulec(id),
ruleNid BIGINT DEFAULT NULL references rulen(id));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id'));
INSERT INTO rulec (id) VALUES (nextval('s_rulec_id'));
INSERT INTO rulec (id) VALUES (nextval('s_rulec_id'));
INSERT INTO rulec (id) VALUES (nextval('s_rulec_id'));
INSERT INTO rule (name,ruleBid) VALUES ('B 1',1);
INSERT INTO rule (name,ruleBid) VALUES ('B 2',2);
INSERT INTO rule (name,ruleBid) VALUES ('B 4',3);
INSERT INTO rule (name,ruleBid) VALUES ('B 4',4);
INSERT INTO rule (name,ruleBid) VALUES ('B 5',5);
INSERT INTO rule (name,ruleBid) VALUES ('B 6',6);
INSERT INTO rule (name,ruleCid) VALUES ('c 1',1);
INSERT INTO rule (name,ruleCid) VALUES ('C 2',2);
INSERT INTO rule (name,ruleCid) VALUES ('C 3',3);
select * from rule
Run Code Online (Sandbox Code Playgroud)