【问题标题】:Am I supposed to index a foreign key? Should I use the primary key for this table?我应该索引外键吗?我应该使用这个表的主键吗?
【发布时间】:2011-12-22 04:05:35
【问题描述】:
CREATE TABLE titlexplan(
  id INTEGER NOT NULL,
  title_id INTEGER NOT NULL ,
  plan_id INTEGER NOT NULL ,
  start_date DATETIME NOT NULL,
  end_date DATETIME
  CHECK (start_date < end_date),
  PRIMARY KEY(id),
  INDEX (title_id),
    FOREIGN KEY (title_id)
    REFERENCES title(id)
  INDEX (plan_id),
    FOREIGN KEY (plan_id)
    REFERENCES plan(id)    
);

这是我正在使用的代码,但出现语法错误:#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INDEX (plan_id), FOREIGN KEY (plan_id) REFERENCES plan(id) )' at line 10

我正在尝试在其他表中的相应 ID 更新时更新 title_id 和 plan_id,并且我正在尝试跟踪更改。

我无法找到一个明确的指南来说明如何执行此操作,这些查询部分有效,但不是全部有效。我认为我不需要此表中的主键,但当我不使用主键时会收到警告:“Warning, table contains no primary key”。所以,我只是添加了“id”列。不过,我不认为它实际上是需要的。

请指教。

谢谢。

【问题讨论】:

  • 你得到的错误是因为一个 mssing 逗号:REFERENCES title(id) ,

标签: mysql database-design foreign-keys timestamp primary-key


【解决方案1】:
CREATE TABLE titlexplan(
  id INTEGER NOT NULL,
  title_id INTEGER NOT NULL ,
  plan_id INTEGER NOT NULL ,
  start_date DATETIME NOT NULL,
  end_date DATETIME
  CHECK (start_date < end_date),
  PRIMARY KEY(id),

  FOREIGN KEY (title_id)
  REFERENCES title(id)
  ON UPDATE CASCADE,

  FOREIGN KEY (plan_id)
  REFERENCES plan(id)
  ON UPDATE CASCADE
);

我相信这应该可行。 “ON UPDATE CASCADE”将导致这些外键在它们引用更新的任何时候更新。

还要确保您使用 innoDB 引擎以使外键正常工作。

如果您不想要 id 列并且 title_id 和 plan_id 的组合始终是唯一的,您可以这样做

CREATE TABLE titlexplan(
  title_id INTEGER NOT NULL ,
  plan_id INTEGER NOT NULL ,
  start_date DATETIME NOT NULL,
  end_date DATETIME
  CHECK (start_date < end_date),
  PRIMARY KEY(title_id, plan_id),

  FOREIGN KEY (title_id)
  REFERENCES title(id)
  ON UPDATE CASCADE,

  FOREIGN KEY (plan_id)
  REFERENCES plan(id)
  ON UPDATE CASCADE   
);

【讨论】:

  • 为什么在第二个示例中将它们都设为主 ID,Clay?
  • 我这样做是为了让您不必创建额外的“ID”列作为主键。相反,您可以让主键由 title_id 和 plan_id 的组合表示,只要该组合始终是唯一的
  • 这很有趣。我不知道 SQL 可以做到这一点。感谢您的酷提示,Clay。
【解决方案2】:

Clay 向您展示了如何进行级联,所以让我添加以下内容:

在外键上创建索引通常是个好主意。如果你正在做一个级联,你真的应该这样做。

我认为标准 SQL 中没有任何方法可以将索引创建为 CREATE TABLE 的一部分。 (MYSQL 可能有一个扩展来做到这一点——我承认我没有检查。)所以你应该单独创建索引。

create index idx_titlexplan_title on titlexplan (title_id);
create index idx_titlexplan_plan on titlexplan (plan_id);

【讨论】:

  • 另外,这是什么命名约定? idx_titlexplain_title 似乎是一个非常尴尬的索引名称。呵呵
  • 我注意到如果我不这样写它就行不通。我知道你是怎么做到的。
  • 在大多数情况下,在外键上建立索引是个好主意,因为您经常希望检索具有给定外键的所有记录。索引使这很有效。在这种情况下,您是否会定期查找具有给定 Planid 的所有 Titlexplan 记录?如果是这样,该字段上的索引会有所帮助。如果您有级联,那么只要 id 更改或关联的记录被删除,db 就必须找到具有给定 planid 的所有记录。所以索引有帮助。 (续...)
  • (续)当然,有时这不是真的。也许您总是或几乎总是首先获得 Titlexplan 记录,然后从那里转到 Plan 记录,而从不从 Plan 转到 Titlexplan。在这种情况下,外键上的索引将是多余的。
  • RE 命名约定:我在示例中使用的名称当然只是示例。尽管如此,我还是经常使用这样的命名约定:“idx”表示它是一个“普通”索引(与主键相反,我使用“pk”),然后是表名,然后是一些字段的指示或字段正在被索引。然后,您可以查看索引列表并很好地了解它们都是什么。我认为这是一个很好的命名约定,但如果它不适合你,好吧,使用别的东西。 :-)
【解决方案3】:

由于缺少逗号,您会收到该错误:

...  
  INDEX (title_id),
    FOREIGN KEY (title_id)
    REFERENCES title(id)  ,        ---  <---- missing comma here
  INDEX (plan_id),
    FOREIGN KEY (plan_id)
    REFERENCES plan(id) 
);

另一件事是您拥有的CHECK 约束:

CHECK (start_date < end_date),

这将不会产生任何错误,但 SQL 引擎将不会检查该约束。正如 MySQL 文档在 CREATE TABLE, CHECK constraints 中解释的那样:

CHECK 子句被所有存储引擎解析但忽略。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 2016-06-30
    相关资源
    最近更新 更多