每个用户的记录数量有限的分层结构

Guf*_*ran 6 postgresql database-design hierarchy

我正在为附属网络规划架构。对于所有分层查询,我都使用 Postgrestablefunc扩展,但这是另一个问题。
任何用户最多只能推荐 3 个其他用户。
所以例如我有这样的用户关系:

CREATE TABLE users
(
  id serial NOT NULL,
  referred_by integer NOT NULL,
  created_at time without time zone NOT NULL,
  updated_at time without time zone NOT NULL,
  CONSTRAINT primary_key PRIMARY KEY (id),
  CONSTRAINT referred_foreign FOREIGN KEY (referred_by)
      REFERENCES users (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE
)
Run Code Online (Sandbox Code Playgroud)

我可以使用connectby函数来查询任何层次结构。但是当涉及到插入相关模型时,我必须检查用户在插入任何新用户之前是否还没有推荐其他 3 个用户。如果他已经有 3 个用户,那么它需要将树级联起来并将其作为树的叶节点,这对于在更大的层次结构上运行是进一步的繁重查询。

用于将新用户级联到叶节点是否可以确定可以放置新用户的最近节点?例如如果这是表中的数据:

                    ____________ A ___________
                   /             |            \
                __ B __       __ C __     ____ D ____
               /   |   \     /   |   \   /     |     \
              E    F    G    H   I   J   K     L
Run Code Online (Sandbox Code Playgroud)

A又引用了一个用户,现在,由于A他的下线已经完全饱和,他下面的任何新用户都应该沿着树级联,并且有9个地方可以放置新用户。

E    F    G    H    I    J    K    L    D
Run Code Online (Sandbox Code Playgroud)

其中最近的节点是D,所以传入节点应该在 D 而不是 E,F..K,L 下

我有3个问题:

  1. 最重要的是,是否可以限制每个用户下的记录数?我不想依赖触发器来检查记录数并在需要时向下级联。如有必要,我可以更改设计。
  2. 在确定根节点饱和后,如何“有效”获取任何树的最近叶节点?高效是指同一查询每分钟可能需要运行几百次,并且数据集没有深度限制。再次,如果有的话,我愿意接受设计建议。
  3. 是否可以为其创建部分索引,referred_foreign以便第一个不会被任何人引用的用户仍然可以满足外部完整性?

有没有更好的设计或我缺少的东西?(我知道我错过了很多只是不知道它是什么)

A-K*_*A-K 2

以下要求可以在有约束的情况下轻松实现:任何用户最多只能推荐 3 个其他用户。

    CREATE TABLE users
    (
      id serial NOT NULL,
      reference_number SMALLINT NOT NULL,
      CONSTRAINT CHK_reference_number CHECK(reference_number BETWEEN 1 AND 3),
      CONSTRAINT UNQ_reference_number UNIQUE(id, reference_number),
      referred_by integer NOT NULL,
(snip)
Run Code Online (Sandbox Code Playgroud)

请注意,您的设计不会阻止循环。我们也可以通过约束轻松地强制执行这一点。如果您有兴趣,我可以详细说明。

关于寻找合格后代的效率,我们可以添加一些冗余数据并获得更好的速度。例如,E 是 A 的后代,但不是直系后代 - B 位于它们之间。我们可以存储以下行:

Ancestor: A
AncestorLevel: 1
Descendant: B
DescendantLevel: 2

Ancestor: B
AncestorLevel: 2
Descendant: E
DescendantLevel: 3

Ancestor: A
AncestorLevel: 1
Descendant: E
DescendantLevel: 3
Run Code Online (Sandbox Code Playgroud)

一旦我们有了这些冗余数据,查找后代就变得简单快捷——只需一个简单的查询,无需递归。当然,采用这种方法我们需要更多的存储空间。

当然,冗余数据总是存在不一致的风险。我们可以使用约束来强制冗余数据的完整性。这很复杂但可行。