#python #sql #django #performance #sqlite
#python #sql #django #Производительность #sqlite
Вопрос:
У меня проблемы с производительностью запроса Django. Предположим, у меня есть 3 модели, и у меня есть 100 строк в таблице Company:
from django.db import models
class Company(models.Model):
name = models.CharField()
def order_count(self):
return self.orders.count()
def order_sum(self):
return (self.orders.all().aggregate(models.Sum('total')))['total__sum']
class Customer(models.Model):
company = models.ForeignKey(Company, related_name="customer", on_delete=models.PROTECT)
name = models.CharField()
def order_count(self):
return self.orders.count()
class Order(models.Model):
company = models.ForeignKey(Company, related_name='orders')
customer = models.ForeignKey(Customer, related_name="orders")
value = models.FloatField()
Я хочу, чтобы в моем шаблоне отображалось название компании и сумма ее заказов, затем для каждого клиента этой компании я хочу показать имя клиента с количеством их заказов.
Мой код запроса views.py
использует предварительную выборку следующим образом:
queryset = Company.objects.prefetch_related(
models.Prefetch('customer',
queryset=Customer.objects.prefetch_related('orders')), 'orders')
Мой псевдокод для template
:
for company in queryset:
print(company.name, company.order_count, company.order_sum)
for customer in company:
print(customer.name, customer.order_count)
Я проверил с помощью панели инструментов отладки Django, она принимает 105 запросов, с этим предложением SQL (псевдокод):
SELECT * FROM company
SELECT * FROM customer WHERE customer.company_id IN (100 IDs of the companies)
SELECT * FROM order WHERE order.customer_id IN (the IDs from previous command)(this duplicates 2 times)
SELECT * FROM order WHERE order.company_id IN (100 IDs of the companies)
SELECT SUM(order.value) FROM order WHERE order.company_id = %s (this duplicates 100 times, for each company's id)
Как показывает панель инструментов отладки Django (DjDT):
- Первые 5 запросов приходят, когда я оцениваю набор запросов (цикл for в шаблоне)
- Следующие 100 запросов приходят, когда я запрашиваю order_sum() (строка 2 в шаблоне) При этом DjDT показывает мне, что это занимает около 700-800 мс (некоторые процессы в шаблоне, но, похоже, это занимает не так много времени, я проверял). Я хочу уменьшить его до 500 мс.
Итак, мои вопросы:
- Что я мог бы сделать, чтобы улучшить ситуацию?
- Почему третий SQL-запрос дублируется 2 раза.
- Есть ли какой-либо способ сократить последний SQL-запрос до 1 запроса?. Я новичок, поэтому, пожалуйста, помогите ^^.
#Большое спасибо за ваше время ^^
Ответ №1:
Вы можете использовать функцию аннотирования, чтобы получить сумму заказа в одном запросе. Например
queryset = Company.objects.annotate(
order_sum=Sum("orders__value")
).prefetch_related(
models.Prefetch('customer', queryset=Customer.objects.prefetch_related('orders')), 'orders'
)
Затем вы можете получить доступ к значению order_sum, как и к другим атрибутам, используя оператор dot
for company in queryset:
print(company.order_sum)
Вы можете прочитать документы Django для большего понимания