如何提升数据库查询的速度和性能?

huangapple go评论73阅读模式
英文:

How can I improve the speed and performance of database queries?

问题

I'm currently working on a Django project where I'm encountering performance issues, especially as my application scales. To provide better context, I've included a realistic code snippet below that represents a performance-intensive section of my application:

在我的Django项目中,我目前遇到了性能问题,特别是随着我的应用程序扩展。为了提供更好的背景,我在下面包含了一个真实的代码片段,代表了我的应用程序中一个性能密集的部分:

from django.db import models

class Order(models.Model):
    # Fields and relationships...

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

class Product(models.Model):
    # Fields and relationships...

def calculate_total_price(order_id):
    order_items = OrderItem.objects.filter(order_id=order_id).select_related('product')
    total_price = 0

    for item in order_items:
        product_price = item.product.price
        quantity = item.quantity
        total_price += product_price * quantity

    return total_price

In the above code snippet, I have an Order model that is associated with multiple OrderItems, and each OrderItem references a Product. The calculate_total_price function is used to calculate the total price for a given order by iterating over its associated OrderItems. However, as the number of OrderItems increases, the calculation becomes significantly slower.

在上面的代码片段中,我有一个与多个OrderItems关联的Order模型,每个OrderItem引用一个Product。calculate_total_price函数用于通过迭代其关联的OrderItems来计算给定订单的总价。但是,随着OrderItems数量的增加,计算变得明显较慢。

I would greatly appreciate any insights and suggestions on how to optimize this code snippet or any other general Django performance tips. Are there any specific techniques, database query optimizations, caching mechanisms, or Django features I should consider to enhance the performance of this code? Additionally, if there are any profiling tools or libraries you recommend for identifying and resolving performance issues, please let me know.

我非常感谢您对如何优化这段代码或任何其他有关Django性能的建议和见解。是否有任何特定的技巧、数据库查询优化、缓存机制或Django功能,我应该考虑以提高此代码的性能?另外,如果有任何性能问题的识别和解决工具或库,您可以推荐吗?请告诉我。

I'm not sure what to do about the performance issues so I don't know where to begin optimizations.

我不确定如何处理性能问题,所以我不知道从哪里开始优化。

Edit
Including example view code:

编辑
包括示例视图代码:

class OrderDetailView(View):
    template_name = 'order_detail.html'

    def get(self, request, order_id):
        order = Order.objects.get(id=order_id)
        total_price = calculate_total_price(order_id)
        context = {
            'order': order,
            'total_price': total_price
        }
        return render(request, self.template_name, context)

If you have any more specific questions or need further assistance, please feel free to ask.

如果您有更具体的问题或需要进一步的帮助,请随时提问。

英文:

I'm currently working on a Django project where I'm encountering performance issues, especially as my application scales. To provide better context, I've included a realistic code snippet below that represents a performance-intensive section of my application:

from django.db import models

class Order(models.Model):
    # Fields and relationships...

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

class Product(models.Model):
    # Fields and relationships...

def calculate_total_price(order_id):
    order_items = OrderItem.objects.filter(order_id=order_id).select_related('product')
    total_price = 0

    for item in order_items:
        product_price = item.product.price
        quantity = item.quantity
        total_price += product_price * quantity

    return total_price

In the above code snippet, I have an Order model that is associated with multiple OrderItems, and each OrderItem references a Product. The calculate_total_price function is used to calculate the total price for a given order by iterating over its associated OrderItems. However, as the number of OrderItems increases, the calculation becomes significantly slower.

I would greatly appreciate any insights and suggestions on how to optimize this code snippet or any other general Django performance tips. Are there any specific techniques, database query optimizations, caching mechanisms, or Django features I should consider to enhance the performance of this code? Additionally, if there are any profiling tools or libraries you recommend for identifying and resolving performance issues, please let me know.

I'm keen to learn best practices and advanced techniques for optimizing Django performance, as I want to ensure my application performs efficiently as it grows. Thank you in advance for your valuable assistance!

I'm not sure what to do about the performance issues so I don't know where to begin optimisations.

Edit
Including example view code:

class OrderDetailView(View):
    template_name = 'order_detail.html'

    def get(self, request, order_id):
        order = Order.objects.get(id=order_id)
        total_price = calculate_total_price(order_id)
        context = {
            'order': order,
            'total_price': total_price
        }
        return render(request, self.template_name, context)

答案1

得分: 3

你可以使用聚合函数而不是循环遍历每个项目来计算订单的总价格。

在你的情况下,你可以将函数重写如下:

from django.db.models import Sum, F

def calculate_total_price(order_id):
    total_price_obj = OrderItem.objects.filter(order_id=order_id).aggregate(total_price=Sum(F('item__product__price') * F('item__quantity')))
    total_price = total_price_obj.get('total_price') or 0
    return total_price

在获取总价格时,我使用了 or 0,以便在查询集为空时将总价格设置为 0。如果不使用它,你将得到 None 作为总价格,这可能会在你的代码库中后续引发异常。

英文:

You can calculate the total price of the order using aggregate rather than looping over each item.

In your case, you can rewrite the function as follows:

from django.db.models import Sum, F

def calculate_total_price(order_id):
    total_price_obj = OrderItem.objects.filter(order_id=order_id).aggregate(total_price=Sum(F('item__product__price') * F('item__quantity')))
    total_price = total_price_obj.get('total_price') or 0
    return total_price

Here I am using or 0 while fetching the total price to set the total price = 0 if the queryset is empty. Without using it you'll get None as total price which might throw an exception in your codebase later on.

答案2

得分: 2

你可以通过数据库本身来计算这个值,甚至可以在获取订单的同一查询中进行计算:

from django.db.models import F, Sum, Value
from django.db.models.functions import Coalesce
from django.shortcuts import get_object_or_404

class OrderDetailView(View):
    template_name = 'order_detail.html'

    def get(self, request, order_id):
        order = get_object_or_404(
            Order.objects.annotate(
                total_price=Coalesce(
                    Sum(
                        F('orderitem__quantity') * F('orderitem__product__price')
                    ),
                    Value(0),
                )
            ),
            id=order_id,
        )
        context = {
            'order': order,
        }
        return render(request, self.template_name, context)

在模板中,你可以使用 {{ order.total_price }} 来渲染这个值。

英文:

You can calculate this by the database itself, even in the same query as the one where you fetch the order with:

<pre><code>from django.db.models import F, Sum, Value
from django.db.models.functions import Coalesce
from django.shortcuts import get_object_or_404

class OrderDetailView(View):
template_name = 'order_detail.html'

def get(self, request, order_id):
    order = get_object_or_404(
        Order.objects.annotate(
            total_price=Coalesce(
                &lt;b&gt;Sum(
                    F(&#39;orderitem__quantity&#39;) * F(&#39;orderitem__product__price&#39;)
                )&lt;/b&gt;,
                Value(0),
            )
        ),
        id=order_id,
    )
    context = {
        &#39;order&#39;: order,
    }
    return render(request, self.template_name, context)&lt;/code&gt;&lt;/pre&gt;

in the template you then render this with {{ order.total_price }}.


> Note: It is often better to use <code>get_object_or_404(&hellip;)</code>&nbsp;<sup>[Django-doc]</sup>,
> then to use <code>.get(&hellip;)</code>&nbsp;<sup>[Django-doc]</sup> directly. In case the object does not exists,
> for example because the user altered the URL themselves, the <code>get_object_or_404(&hellip;)</code> will result in returning a HTTP 404 Not Found response, whereas using
> <code>.get(&hellip;)</code> will result in a HTTP 500 Server Error.


> Note: Subclassing the View class directly is often not necessary. In this case your view looks like a DetailView&nbsp;<sup>[Django-doc]</sup>. By using a DetailView instead of a simple View, you often do not have to implement a lot of boilerplate code.

答案3

得分: -1

将数据库从SQLite切换到PostgreSQL以提升性能和效率。

英文:

Switch from SQLite to PostgreSQL as your database to improved performance and efficiency

huangapple
  • 本文由 发表于 2023年6月29日 17:51:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76579941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定