Python 许多人在Django行动缓慢
我有两个简单的模型:Python 许多人在Django行动缓慢,python,django,postgresql,Python,Django,Postgresql,我有两个简单的模型: class A(models.Model): name_a = models.CharField( _("name_a"), max_length=255) b = models.ManyToManyField( 'B', related_name='a', blank=True ) class B(models.Model): name_b = models.CharField(
class A(models.Model):
name_a = models.CharField(
_("name_a"),
max_length=255)
b = models.ManyToManyField(
'B',
related_name='a',
blank=True
)
class B(models.Model):
name_b = models.CharField(
_("name_b"),
max_length=255)
我创建了1000条记录用于:
for i in range(1000):
A.objects.create()
和B的3个对象:
for i in range(3):
B.objects.create()
并通过m2m关系将b的每个对象与a的每个对象连接起来:
for a in A.objects.all().iterator():
a.b.add(B.objects.all()[0])
a.b.add(B.objects.all()[1])
a.b.add(B.objects.all()[2])
现在,对于每个a对象,我想得到所有b对象:
import time
start = time.time()
objects = A.objects.all()
for n in objects.iterator():
list(n.b.all())
print(time.time() - start)
Output: 2.642864465713501
因此,仅对1000个对象执行此查询需要2秒以上的时间。表演太糟糕了。我在生产中有超过1000000件物品
我试图通过使用预回迁来提高性能:
import time
start = time.time()
objects = A.objects.all().prefetch_related('b')
for n in objects.iterator():
list(n.b.all())
print(time.time() - start)
Output: 2.684298038482666
但这毫无帮助。为什么速度如此之慢?如何提高性能?来自Django文档
请注意,如果使用迭代器()运行查询,则将忽略与预回迁相关的()调用,因为这两种优化在一起没有意义
当运行这个程序时,使用sqlite大约需要0.7秒。如果我省略了为每个查询创建列表,时间会减少50% 关键是,你点击DB的次数与你点击
A
对象的次数相同。
因此,提高性能的最佳选择是减少查询数量。
但在这里,你到底打算做什么其实很重要。
由于这一点尚不清楚,从现在开始,或多或少只是猜测什么对你有用
可能只是在A.objects.values\u list('id')
中迭代,然后查询B
,因为您并不真正使用A
对象:
bq = B.objects.all()
for a_id, in A.objects.values_list('id').iterator():
list(bq.filter(b__id=a_id)) # maybe correct your related_name to 'a' so this would look a__id=a_id
print(time.time() - start)
或
如果您只想要与某些a
对象相关的所有b
对象,例如,所有带有name\u a
的对象都包含'foo'
:
B.objects.filter(b__name_a__contains='foo').all().distinct()
希望这些建议能有所帮助这与您的实际问题无关,但您的
相关名称
可能应该是'a'
而不是'b'
。目光敏锐;-)谢谢你说得对,我没有说清楚我的意图。我需要序列化A和B对象。所以我需要一个ASerializer类。我认为序列化程序也只是在所有对象(如上面的代码)上循环并序列化它们。我发现serializer.data调用也需要2秒以上的时间。所以我只想通过手动进行数据库调用(使用python的list方法)来调试它。
B.objects.filter(b__name_a__contains='foo').all().distinct()