应该使用代理PK加上一个唯一的列还是使用唯一列的自然PK?

时间:2016-05-20 03:53:51

标签: mysql sql database-design

鉴于:tX_1.name永远不能为NULL,可变长度最多为45个字符,且必须始终唯一。

哪些因素会影响是否应使用代理PK加上一个唯一列(架构1),或者使用第一个表的唯一列作为其PK(架构2)的PK自然键是什么?

enter image description here 架构1

CREATE TABLE IF NOT EXISTS t1_1 (
  idt1_1 INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(45) NOT NULL,
  data VARCHAR(45) NULL,
  PRIMARY KEY (idt1_1),
  UNIQUE INDEX name_UNIQUE (name ASC))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t1_2 (
  idt1_2 INT NOT NULL AUTO_INCREMENT,
  t1_1_idt1_1 INT NOT NULL,
  data VARCHAR(45) NULL,
  PRIMARY KEY (idt1_2),
  INDEX fk_t1_2_t1_1_idx (t1_1_idt1_1 ASC),
  CONSTRAINT fk_t1_2_t1_1
    FOREIGN KEY (t1_1_idt1_1)
    REFERENCES t1_1 (idt1_1)
    ON DELETE CASCADE
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t1_3 (
  idt1_3 INT NOT NULL AUTO_INCREMENT,
  data VARCHAR(45) NULL,
  PRIMARY KEY (idt1_3))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t1_1_has_t1_3 (
  t1_1_idt1_1 INT NOT NULL,
  t1_3_idt1_3 INT NOT NULL,
  PRIMARY KEY (t1_1_idt1_1, t1_3_idt1_3),
  INDEX fk_t1_1_has_t1_3_t1_31_idx (t1_3_idt1_3 ASC),
  INDEX fk_t1_1_has_t1_3_t1_11_idx (t1_1_idt1_1 ASC),
  CONSTRAINT fk_t1_1_has_t1_3_t1_11
    FOREIGN KEY (t1_1_idt1_1)
    REFERENCES t1_1 (idt1_1)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT fk_t1_1_has_t1_3_t1_31
    FOREIGN KEY (t1_3_idt1_3)
    REFERENCES t1_3 (idt1_3)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

架构2

CREATE TABLE IF NOT EXISTS t2_1 (
  name VARCHAR(45) NOT NULL,
  data VARCHAR(45) NULL,
  PRIMARY KEY (name))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t2_2 (
  idt2_2 INT NOT NULL AUTO_INCREMENT,
  t2_1_name VARCHAR(45) NOT NULL,
  data VARCHAR(45) NULL,
  PRIMARY KEY (idt2_2),
  INDEX fk_t2_2_t2_11_idx (t2_1_name ASC),
  CONSTRAINT fk_t2_2_t2_11
    FOREIGN KEY (t2_1_name)
    REFERENCES t2_1 (name)
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t2_3 (
  idt2_3 INT NOT NULL AUTO_INCREMENT,
  data VARCHAR(45) NULL,
  PRIMARY KEY (idt2_3))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS t2_1_has_t2_3 (
  t2_1_name VARCHAR(45) NOT NULL,
  t2_3_idt2_3 INT NOT NULL,
  PRIMARY KEY (t2_1_name, t2_3_idt2_3),
  INDEX fk_t2_1_has_t2_3_t2_31_idx (t2_3_idt2_3 ASC),
  INDEX fk_t2_1_has_t2_3_t2_11_idx (t2_1_name ASC),
  CONSTRAINT fk_t2_1_has_t2_3_t2_11
    FOREIGN KEY (t2_1_name)
    REFERENCES t2_1 (name)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT fk_t2_1_has_t2_3_t2_31
    FOREIGN KEY (t2_3_idt2_3)
    REFERENCES t2_3 (idt2_3)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

1 个答案:

答案 0 :(得分:0)

t1和t3之间的多对多关系在某些方面效率低下。请参阅my blog

我经常使用UNIQUE键来表示PK。我回顾了我设计的大量表格;只有1/3的PK有AUTO_INCREMENT。一些注意事项(假设 InnoDB):

  • 每个二级密钥包括PK的所有列;这个可能会导致庞大。
  • 由于PK的“聚类”,PK查找行比使用辅助键更快。
  • FOREIGN KEYs有成本 - 执行查找以检查隐含的“约束”。通常以不会发生FK违规的方式编写代码,从而使FK成为不必要的开销。 (其他人说FKs'很好'。)
  • 一千行的表太小,以至于这些问题不是很重要。一百万行将使它们变得重要。十亿行,我们需要讨论更多的事情。

回到你的问题......

INT是4个字节; VARCHAR是可变的,您没有提供平均长度。因此,很难比较。您的架构变得更加复杂。您添加更多列和更多索引,因此我对二级索引的评论的相关性尚未确定。你可能认为45还不够。等等。

底线:翻转硬币以决定从哪个Schema开始,然后在Schema成熟时学习。