0

我的理解是,在网站/数据库上注册新用户的方法是在用户表中创建一个新条目。此后,每当我们想从另一个数据表中检索特定的用户数据时,我们都必须查询用户表以获取我们的用户 ID(当然,如果它还没有存储),在针对我们的数据的新查询中使用该 ID桌子。如果有人想要更模块化的设计,我们可以为每个新用户创建一个新数据库,尽管这不像第一种方法那样流行。我不确定我的理解是否正确,所以请在您认为合适的地方纠正我。

我正在思考的是,在恰好是我最喜欢的播放器的 PostgreSQL 中,您可以使用模式。模式就像数据库中的数据库。然后,当您进行查询时,您可以在表名前加上模式名称,并在其间添加一个点。就像模式是一个类并且您想要访问其中的静态属性一样。我只是喜欢这个符号!

..那么为什么我没有一个数据库来存储与管理相关的东西,甚至可能是一个用户表。但是我有另一个仅用于用户数据的数据库,每个用户都有自己的模式。然后,我需要在我的 PHP:s 用户类中存储的只是一个保存此模式名称的变量,并且每次要从数据库中检索用户特定数据时,都会使用此变量。

注册新用户的最佳做法是什么,该做什么和不该做什么?您能看到架构设计的任何优点或缺点吗?

编辑

因为这个问题让我对我的最终目标感到有些困惑,所以我将在这里澄清我的问题。实际上,数据库设计有点复杂,但是假设我的 Web 应用程序中有三个类。其中一个,在此称为 Foo,可选地与其他两个 Bar1 和 Bar2 处于 has-a 关系。我网站的注册用户可以“创建”任意数量的 Foo、Bar1 和 Bar2,它们相互独立。

Foo 当前存储在数据库中的多个表中。这是他的主表,其中有一个递增的序列:

TABLE foo
(
  foo_id serial NOT NULL,
  title text
  CONSTRAINT foo_pk PRIMARY KEY (foo_id)
)

让我们不要深入研究任何其他表的细节或 Bar 的存储方式。我已经注意只有尽可能少的表,但是,我仍然必须根据实体关系及其约束来设计数据库。

Foo 可能取决于任何 Bar1 和 Bar2 的存在。Foo 也可以拥有任意数量的 Bar1 和 Bar2。所以这里有两张表来说明这种所有权:

TABLE foo_has_bar1
(
  foo_id integer NOT NULL,
  bar1_id integer NOT NULL
  CONSTRAINT foo_has_bar1_pk PRIMARY KEY (foo_id, bar1_id),
  CONSTRAINT foo_has_bar1_fk1 FOREIGN KEY (foo_id) REFERENCES foo (foo_id),
  CONSTRAINT foo_has_bar1_fk2 FOREIGN KEY (bar1_id) REFERENCES bar1 (bar1_id)
)

TABLE foo_has_bar2
(
  foo_id integer NOT NULL,
  bar2_id integer NOT NULL
  CONSTRAINT foo_has_bar2_pk PRIMARY KEY (foo_id, bar2_id),
  CONSTRAINT foo_has_bar2_fk1 FOREIGN KEY (foo_id) REFERENCES foo (foo_id),
  CONSTRAINT foo_has_bar2_fk2 FOREIGN KEY (bar2_id) REFERENCES bar2 (bar2_id)
)

目前,我在任何地方都没有注册用户的 user_id 列。我一直认为我应该将用户数据与模式分开,这些模式当然与 user_id 一起存储在另一个数据库或公共模式中。Catcall在此线程的答案中也以某种方式这么说,我引用:

“模式是 PostgreSQL 数据库中的命名空间。”

[..]

“如果每个用户都有专用于该用户的数据库对象,您可以轻松地捍卫每个用户实施一个模式的决定 [..]。”

所以我很关心,最佳实践是什么?根据这个线程中所有答案的感觉,我什至不应该考虑使用单独的模式。但是,对于将 object_id 与 user_id [1]联系在一起的每种类型的对象,我是否不必再多一张表?它目前是可以管理的,但我仍然可以看到这将如何使我的“命名空间”变得混乱,而不仅仅是拥有单独的模式。

[1]在 PostgreSQL 中,如果每一行代表一个用户,并且 user_id 之后的每个连续列是一个具有标识对象关系的整数数组的列,我可以将其分解为一个表。但是我对 PostgreSQL 数组(在 PHP 中读取和修改它们)的经验非常糟糕,而且我认为处理它们会比多个表慢。

4

3 回答 3

2

我建议不要这样做。

您最终会得到许多架构,每个架构都针对每个用户。如果您想查询所有这些用户的某些内容,您将不得不跳过箍。

让我举个例子:假设您为每个用户存储他登录的次数。现在您想知道所有用户登录的次数。

我建议您只需为每个要存储的实体使用 1 个表,并为其添加一个用户 ID。

CREATE TABLE tbluserdata(
  userdataid SERIAL PRIMARY KEY,
  userid integer REFERENCES tblusers(userid),
  nroflogins integer,
  mydata TEXT,
  whatever integer,
  etc. etc.
);

并在每个查询中使用用户 ID。在我看来更干净。

于 2012-10-02T10:47:18.897 回答
2

我的理解是,在网站/数据库上注册新用户的方法是在用户表中创建一个新条目。此后,每当我们想从另一个数据表中检索特定的用户数据时,我们都必须查询用户表以获取我们的用户 ID

通常,您会将登录用户的 id 存储在应用程序变量中。完成此操作后,您无需查询数据库。对于 Web 应用程序,此类内容通常存储在会话变量或 cookie 中。请注意,用户不能简单地键入任意 ID 号来访问其他人的数据。

如果有人想要更模块化的设计,我们可以为每个新用户创建一个新数据库,尽管这不像第一种方法那样流行。我不确定我的理解是否正确,所以请在您认为合适的地方纠正我。

“每个用户一个数据库”是多租户(多客户)数据库设计方法的一个末端。例如,如果您构建了在线会计软件,您可能会合理地选择为每个租户实施一个数据库。这为您提供了最大的数据隔离、最简单的灾难恢复和最大的定制机会。

“每个用户一个数据库”对于多用户数据库设计来说不是一个好的选择。StackOverflow 在这个意义上是一个多用户系统。

模式就像数据库中的数据库。

模式是 PostgreSQL 数据库中的命名空间。如果您构建在线会计软件,您可能会合理地选择为每个租户实施一个模式。您可以在架构级别授予权限,这样您就可以轻松地将一个用户的数据与所有其他用户的数据隔离开来。灾难恢复相当简单——只需恢复一个模式。您可以将共享表、视图和过程放在所有用户也可以读取的单独模式中。

按照设计,PostgreSQL 使得跨数据库查询变得相对困难。跨模式查询相对容易。

“每个用户一个模式”不是多用户数据库设计的好选择。例如,如果 StackOverflow 这样做,最终可能会产生 400 万个模式。

..那么为什么我没有一个数据库来存储与管理相关的东西,甚至可能是一个用户表。但是我有另一个仅用于用户数据的数据库,每个用户都有自己的模式。然后,我需要在我的 PHP:s 用户类中存储的只是一个保存此模式名称的变量,并且每次要从数据库中检索用户特定数据时,都会使用此变量。

如果每个用户都有专用于该用户的数据库对象,您可以轻松地捍卫每个用户实现一个模式的决定,并为共享表、视图、过程等使用准公共模式。这与说它是不同的适合您的应用最佳决定。

“每个用户一个模式”是多租户数据库设计的另一点。

该范围的远端是“每个用户(几乎)共享每张桌子”。每行都带有一个用户标识符,该标识符显示哪个用户拥有每一行。您必须在编码时更加小心,以确保您不会意外地将一个用户的数据暴露给不同的用户。灾难恢复很麻烦。

SO 有一个多租户标签。你可能想让它成为你的最爱之一。我已将该标签添加到您的问题中,因为这似乎是您前进的方向。

于 2012-10-02T13:24:38.840 回答
2

我认为您混淆了您的网络用户和数据库用户。

常见的做法是将用户存储在用户表中。将数据分布在多个模式中将无法进行没有实际好处的有效查询。

CREATE TABLE users (
    id   serial PRIMARY KEY,
    name text NOT NULL
);

做:

  • 存储加密的密码和盐
  • 使用主键加速查询
  • 在插入数据库之前验证数据

不:

  • 以纯文本形式存储密码
  • 信任用户输入
于 2012-10-02T10:58:13.653 回答