Почему Django получает список результатов из query_set слишком поздно?
Я изучаю вопрос о Django ORM. Я не смог найти ответ в поиске, но буду благодарен, если кто-нибудь подскажет мне связанный сайт.
Моя модель выглядит следующим образом. У пользователя1 есть 2 счета, и 500,000 транзакций принадлежат одному из счетов.
class Account(models.Model):
class Meta:
db_table = 'account'
ordering = ['created_at']
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
account = models.CharField(max_length=20, null=False, blank=False, primary_key=True)
balance = models.PositiveBigIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class AccountTransaction(models.Model):
class Meta:
db_table = 'account_transaction'
ordering = ['tran_time']
indexes = [
models.Index(fields=['tran_type', 'tran_time', ]),
]
account = models.ForeignKey(Account, on_delete=models.CASCADE)
tran_amt = models.PositiveBigIntegerField()
balance = models.PositiveBigIntegerField()
tran_type = models.CharField(max_length=10, null=False, blank=False)
tran_detail = models.CharField(max_length=100, null=True, default="")
tran_time = models.DateTimeField(auto_now_add=True)
Время выполнения запроса для вышеуказанной модели следующее.
start = time.time()
rs = request.user.account_set.all().get(account="0000000010").accounttransaction_set.all()
count = rs.count()
print('>>all')
print(time.time() - start) # 0.028000831604003906
start = time.time()
q = Q(tran_time__date__range = ("2000-01-01", "2000-01-03"))
rs = request.user.account_set.all().get(account="0000000010").accounttransaction_set.filter(q)
print('>>filter')
print(time.time() - start) # 0.0019981861114501953
start = time.time()
result = list(rs)
print('>>offset')
print(time.time() - start) # 5.4373579025268555
Результат запроса_set - всего около 3500 записей. (Из 500 000 записей было выбрано 3500). Я сделал ряд вещей, например, установил смещение на результат (rs) query_set, но все равно требуется много времени, чтобы получить фактическое значение из query_set. Я знаю, что представление загружает данные при приближении к фактическим значениям, таким как count(), но что я сделал не так?
From https://docs.djangoproject.com/en/4.1/topics/db/queries/#querysets-are-lazy:
QuerySet ленивы - акт создания QuerySet не включает в себя никакой активности в базе данных. Вы можете складывать фильтры вместе хоть целый день, и Django не будет выполнять запрос до тех пор, пока QuerySet не будет оценивается. Взгляните на этот пример:
q = Entry.objects.filter(headline__startswith="What") q = q.filter(pub_date__lte=datetime.date.today()) q = q.exclude(body_text__icontains="food") print(q)
Хотя это выглядит как три обращения к базе данных, на самом деле это обращение к базе данных только один раз, в последней строке. базе данных только один раз, в последней строке (print(q)). В общем случае результаты набора запросов не извлекаются из базы данных, пока вы не "попросите" о них. Когда вы это делаете, QuerySet оценивается путем обращения к базе данных. Подробнее о том, когда именно происходит оценка, см. Когда наборы запросов оцениваются.
В вашем примере база данных попадает в базу только при вызове list(rs)
, вот почему это занимает так много времени.