引用表应该有主键、自动增量还是索引?

Ian*_* Y. 4 database-design

我正在尝试实现一个列表。每个列表项将与一个或多个标签相关联。每个标签将与一个或多个列表项相关联。

我对这个领域还是很陌生。幸运的是,我设法在这个问题中找到了一个解决方案,其答案表明了以下数据库设计:

Articles table
- id
- name
- etc

Relational Tag Arts table
- Fkey tags id
- Fkey article id

Tags table
- id
- name
- etc
Run Code Online (Sandbox Code Playgroud)

我已经创建了我的三个表。现在我不明白的是,引用表(包含两个外键的表)是否应该具有主键、自动增量或索引?

[已解决]虽然我不是 100% 确定,但我猜参考表的内容是故意“重复”的。例如,如果我添加一个与 5 个标签相关联的新项目,那么引用表应该再添加 5 个记录,这些记录都具有相同的项目 ID,但具有不同的标签 ID。我对么?

Len*_*art 9

您可能需要考虑退后一步来考虑设计过程。一旦你熟悉了,你通常可以跳过它并直接实现它。我建议从表格开始(理论上称为关系)。你似乎发现了:

* Articles
* Tags
Run Code Online (Sandbox Code Playgroud)

下一步是考虑是什么唯一标识了文章和标签中的行(元组)。这可能是单个列(属性)或列的组合。如果你和某人谈论过一篇文章,你会用什么来识别它?所有这些属性或属性组合都称为候选键。在这个过程中,你可能会选择添加一个人工(代理)键,我假设id就是这样一个属性。例如,添加代理键的原因可能是自然键太复杂、不够稳定等。但您仍应将它们声明为 UNIQUE。

说到 id,我强烈建议您将其命名为 article_id 或类似名称,并通过模型坚持使用该名称。诸如 Id、Name 等名称太模糊而没有意义,并且通常会与您使用的 DBMS 中的保留字相冲突。假设我们已经得出结论:

CREATE TABLE Articles
( article_id ... not null  
, article_name ... not null
, publishing_date date not null
, ...
,    primary key (article_id) -- surrogate key
,    unique ( article_name, publishing_date ) -- natural key
);

CREATE TABLE Tags 
( tag_id ... not null primary key
, tag_name ... not null unique
);
Run Code Online (Sandbox Code Playgroud)

这些表是如何关联的?您似乎已经得出结论,文章和标签之间存在 NN 关系,这通常是通过第三个表(有时称为连接或链接表)来实现的。我们称这个表为:

CREATE TABLE Article_Tags
( article_id ... not null references Articles (article_id)
, tag_id ... not null references Tags (tag_id)

);
Run Code Online (Sandbox Code Playgroud)

现在对于您最初的问题,是什么唯一地标识了这种关系?我会在这里建议一个复合键,如:

CREATE TABLE Article_Tags
( article_id ... not null references Articles (article_id)
, tag_id ... not null references Tags (tag_id)
,     primary key (article_id, tag_id)
);
Run Code Online (Sandbox Code Playgroud)

并且不添加额外的代理键(我什至不确定这种键的用途是什么,但我经常看到它以某种design by blindfold方式添加)。使用建议的组合键,您可以保证对于每篇文章不会多次使用相同的标签。

如果您有时想检索给定标签的所有文章,您可以添加如下索引:

CREATE UNIQUE INDEX ... ON Article_Tags (tag_id, article_id);
Run Code Online (Sandbox Code Playgroud)

编辑:关于索引与键的一些信息

索引是一个物理概念,实际上在 SQL 标准中甚至都没有提到,这意味着每个供应商都可以随心所欲地实现它们,而某种类型的键是一个逻辑概念。请注意,在某些 DBMS 中,这两个概念之间存在模糊的界限,例如,可能有外键引用 SQL-server 中的唯一索引,而 MySQL 调用索引键。

大多数 DBMS:s(以及我认识的每个人)都使用物理索引实现逻辑键(UNIQUE、PRIMARY KEY),因此如果您添加一个键,就会在幕后创建一个索引。以下键是多余的:

PRIMARY KEY (a,b) <=> UNIQUE (b,a)
Run Code Online (Sandbox Code Playgroud)

因为如果 (a,b) 是唯一的,那么 (b,a) 也是唯一的。如果存在另一个,那么您的 DBMS 将不允许您创建一个,这是一个很大的机会。另一方面:

INDEX (a,b) is not redundant with INDEX(b,a)
Run Code Online (Sandbox Code Playgroud)

由于查询如下:

SELECT ... FROM T WHERE a = ?
Run Code Online (Sandbox Code Playgroud)

可以使用第一个索引有效地找到匹配的行,但第二个索引不能。你可以把它想象成你有一个按名字、姓氏组织的索引,你试图找到一个姓盖茨或托瓦尔兹的人。在找到所有具有这些姓氏的人之前,您基本上必须浏览许多名字。

那么为什么不为搜索中使用的每一列创建一个单列索引呢?许多 DBMS 可以执行 INDEX ANDING(但有些不能),但无论如何它比使用一个多列索引效率低。再一次,您可以将其与首先查看 first-name 的索引并发现第 14、50 和 126 页上有一个 Bill 的过程进行比较。然后查看 last-name 的另一个索引并发现有一个 Bill盖茨在第 21、50、123 和 212 页,最后将这两个集合相交得出比尔盖茨可以在第 50 页找到的结论。非常简单地。

您可以使用多列索引 a,b,c,d,e,f 来查找 a、ab、abc 等,但是如果您查找 WHERE d=? 和 f=?。

上面的内容非常简单,但可能会给你一两个关于如何开始思考设计过程的想法。

  • `UNIQUE` 键限制了 `Article` 和 `Tag` 列的组合,以便不允许重复。总是有一行意思是“文章 A 被标签 B 标记”。主键是允许将每一行与所有其他行区分开来的键,例如序列号没有两个项目具有相同的主键。所以唯一性的要求对于PK是强制性的。表可以有多个 UNIQUE 键,但只能将其中一个声明为 PRIMARY。 (2认同)