反向Django外键查找的复杂性

时间:2018-10-28 11:39:04

标签: django django-queryset django-related-manager

假设我有一个这样的模型:

    class Post(models.Model):
         name = models.CharField(max_length=25, unique=True)

    class Picture(models.Model):
         post = models.ForeignKey(to=Post, ondelete=models.CASCADE)
         image = models.ImageField()

现在假设我在执行类似这样的查询:

    p = Post.objects.get(name=foo)
    images = p.picture_set.all()

现在,第一个查询显然会搜索所有帖子,以获取名称为foo的帖子。
但是我想知道第二个。它是在数据库中的所有Picture表中搜索以查找所有具有post=p的图片,还是在第一个查询中获得p时可用的信息?
因为如果是前者,那么我担心可扩展性问题。

1 个答案:

答案 0 :(得分:1)

  

但是我想知道第二个。它是在数据库中的所有“图片”表中搜索以查找所有具有post = p的图片,还是在第一个查询中获得p时可用的信息?

简短答案:默认情况下,ForeignKey添加索引,使检索速度非常快(值的数量为对数,反向记录的数量为线性)。

这取决于数据库是否在ForeignKey上构造索引。默认情况下,Django 会构造一个索引。这意味着它不仅存储表的行,而且还存储数据结构,该数据结构允许快速查找具有特定值的所有行。

索引的实现可以取决于数据库。在MySQL中,默认情况下将使用BTREE,这意味着对于查找值,大约需要 O(log n)来获得集合,而 O( k),其中带有 k 的具有该外键的项数可以全部检索。但是,存在其他索引结构(例如某种哈希表),甚至可以(稍微)更快地进行查找,尽管例如,哈希表对于检索ForeignKey小于给定数字的所有元素并不是那么有效。

您还可以在其他列上添加索引,例如:

class Post(models.Model):
    name = models.CharField(max_length=25, db_index=True, unique=True)

因此,现在检索具有给定名称的所有Post对象也将运行得更快。

使用索引当然不是“免费的”:这意味着每次插入或删除记录时,索引也需要更改(通常还需要 O(log n)) )。如果通过更改外键的值来更新记录,则该索引也需要更改。因此,索引提供了显着的加速,但是应该只将索引放在经常执行查找的列上,因为否则“维护”索引的成本可能大于加速查找过程的收益。 >