理解 / mySQL 又名欺骗 Django 中的 ForeignKey 关系

Posted

技术标签:

【中文标题】理解 / mySQL 又名欺骗 Django 中的 ForeignKey 关系【英文标题】:Understanding / mySQL aka tricking ForeignKey relationships in Django 【发布时间】:2011-10-10 22:34:14 【问题描述】:

所以我继承了一些 django。

mysql 表很简单,其中 parent 不是 FK 关系,只是“Parent”id:

CREATE TABLE `Child` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `parent` int(10) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24;

但后来发起人这样做了..

class Child(models.Model):
    """Project Child information"""
    id = models.AutoField(primary_key=True)
    parent = models.ForeignKey(Parent)
    name = models.CharField(max_length=255)

    class Meta:
        managed = False

诚然,我不是 SQL 骑师,但我知道“真正的”外键关系类似于此通知 CONSTRAINT...

CREATE TABLE `Child` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `child_63f17a16` (`parent_id`),
  CONSTRAINT `parent_id_refs_id_34923e1e` FOREIGN KEY (`parent_id`) REFERENCES `Parent` (`id`)
) ENGINE=InnoDB;

我想知道的是:

    我希望通过这种“诡计”看到什么问题。 虽然这似乎可行 - 是否建议或建议这样做。 是否建议我们将 SQL 修改为 add in the constraint?

非常感谢!

【问题讨论】:

【参考方案1】:

    没有实际约束可能会导致引用损坏、父级无效和其他类型的数据不一致。我不是 Django 专家,但我敢猜测,在大多数情况下,除非您故意添加一些无效记录,否则 Django 仍然可以很好地处理关系。

    通常,如果您的 RDBMS 支持外键约束,则绝对没有理由不使用它们,忽略它们可能会被视为设计缺陷。

    您应该考虑添加键约束。它们不仅可以让您的 DBMS 很好地了解如何优化查询,还可以确保数据的一致性。我很确定 Django 在某处有一个设置,当您运行 manage.py syncdb

    时会自动生成 SQL 以添加键约束

要了解更多关于为什么你应该更喜欢外键的信息,你应该阅读MySQL Foreign Key Documentation

最有趣的是:

InnoDB 需要外键和引用键的索引,以便外键检查可以快速且不需要表扫描。在引用表中,必须有一个索引,其中外键列按相同顺序列为第一列。如果引用表不存在,则会在引用表上自动创建此类索引。 (这与一些旧版本相反,在旧版本中,索引必须显式创建,否则外键约束的创建将失败。)如果给定 index_name,则按前面所述使用。

【讨论】:

这是非常好的信息 - 非常感谢您的详细回复 - 对于没有它的问题,我当然同意您的看法。也就是说,您是否看到将其简单地分配为 FK 而不施加这些约束的问题?它确实让我的查询更简单...... 我不确定您所说的不施加约束是什么意思。在 InnoDB 中,当您拥有 FOREIGN KEY REFERENCES 时,它会自动创建并强制执行存在约束。你不需要CONSTRAINT 子句。 措辞不佳。您是否看到在 Django 中将其定义为 ForeignKey 而不是在 db 级别强加它有任何问题;通知 managed=False Django 不会强制执行约束,它只需要知道它们就可以创建适当的 SQL 和 JOIN 表。除非您手动将索引添加到架构中的所有外键字段,否则您可能还会遇到 JOIN 的性能问题。如果您确实朝着这个方向前进,则需要确保(在视图级别)使用现有/有效外键插入数据,否则您将有孤儿,您仍然会遇到一致性问题。话虽如此,Django 会工作。您可以运行 MyISAM 模式(无 FK);它只是不能确保所有的引用都是有效的。 @alxbl :不理解您评论中的一部分 - “它只需要知道它们,以便它可以创建适当的 SQL 和 JOIN 表”。这什么时候会发生?这有什么用例?【参考方案2】:

它应该更快......因为你 mysql 在子表中添加一行之前不会检查约束。 但是使用外键,它会让你的生活更轻松,因为你可以使用 on update 和 on delete。 我会接受约束。

【讨论】:

除非您手动将索引添加到外键字段,否则它不会更快。但是,如果您要这样做,则不妨一直使用外键。无论哪种方式使用索引,您都将拥有一页 I/O,并且检查约束也是一页 I/O。这意味着插入时可能会有一个小的(通常是微不足道的)缺点,但您可以 100% 确定表中没有损坏的引用。

以上是关于理解 / mySQL 又名欺骗 Django 中的 ForeignKey 关系的主要内容,如果未能解决你的问题,请参考以下文章

python - 使用 Django 将 Unicode 字符存储到 MySQL 时出现问题

新 HTTP 规范 (RFC 7231) 中的“欺骗性请求路由”是啥意思?

Django ORM 能否以可靠的与后端无关的方式存储无符号 64 位整数(又名 ulong64 或 uint64)?

ARP欺骗实践

如何将 PostgreSQL“merge_db”(又名 upsert)函数翻译成 MySQL

无线安全实践入门网络扫描和ARP欺骗