假设我有一个这样的模型:
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
时可用的信息?
因为如果是前者,那么我担心可扩展性问题。
答案 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)) )。如果通过更改外键的值来更新记录,则该索引也需要更改。因此,索引提供了显着的加速,但是应该只将索引放在经常执行查找的列上,因为否则“维护”索引的成本可能大于加速查找过程的收益。 >