Mysql 如何在Django中减少查询时的数据库命中数

Mysql 如何在Django中减少查询时的数据库命中数,mysql,django,django-models,Mysql,Django,Django Models,我有三张桌子 使用者 装置 日志 我想根据设备和日志过滤日志。我正在使用下面的查询,它迭代用户和设备以获取日志。我觉得这将成为一个性能打击。如何减少数据库命中数 for user_obj in User.objects.all(): device_qs = Device.objects.filter(user=user_obj) if device_qs.exists(): for device_obj in device_qs: log_

我有三张桌子

  • 使用者
  • 装置
  • 日志
  • 我想根据设备和日志过滤日志。我正在使用下面的查询,它迭代用户和设备以获取日志。我觉得这将成为一个性能打击。如何减少数据库命中数

    for user_obj in User.objects.all():
        device_qs = Device.objects.filter(user=user_obj)
        if device_qs.exists():
            for device_obj in device_qs:
                log_count = Log.objects.filter(user=user_obj, device=device_obj, created_at__range(from_date, to_date)).count()
    

    我要做的是创建一个“代理模型”,它引用MySQL实例中的
    视图

    视图如下所示:

    SELECT 
    t1.*,
    t2.*,
    t3.*
    FROM users t1
    RIGHT JOIN device t2 (ON t1.id=t2.user_id)
    RIGHT JOIN log t3 (ON t3.device_id=t2.id);
    
    from django.db import connection
    sql = "SELECT * FROM your_view WHERE some_date_column > 'foo' AND some_date_column < 'bar' "
    
    with connection.cursor() as cur:
    
        cur.execute(sql)
        data = cur.fetchall()
    
    print(data)
    
    现在要创建代理模型,请执行以下操作:

    class SomeModel(models.Model):
        # all fields from the 3 tables here
    
        class Meta:
            db_table = 'yourViewNameHere'
            managed = False # this keeps django from creating the table
    
    然后像往常一样
    python manage.py makemigrations
    +
    python manage.py migrate

    现在,要访问所需的数据,您可以执行以下操作:

    SELECT 
    t1.*,
    t2.*,
    t3.*
    FROM users t1
    RIGHT JOIN device t2 (ON t1.id=t2.user_id)
    RIGHT JOIN log t3 (ON t3.device_id=t2.id);
    
    from django.db import connection
    sql = "SELECT * FROM your_view WHERE some_date_column > 'foo' AND some_date_column < 'bar' "
    
    with connection.cursor() as cur:
    
        cur.execute(sql)
        data = cur.fetchall()
    
    print(data)
    
    从django.db导入连接
    sql=“从您的视图中选择*,其中一些日期列>“foo”和一些日期列<“bar”
    将connection.cursor()作为cur:
    当前执行(sql)
    data=cur.fetchall()
    打印(数据)
    
    注意如果要将参数传递给原始sql查询,则应始终这样传递参数,以避免sql注入:

    sql = "SELECT * FROM your_view WHERE some_date_column > %s AND some_date_column < %s"
    
    params = ('foo', 'bar')
    with connection.cursor() as cur:
    
        cur.execute(sql, params)
        data = cur.fetchall()
    
    sql=“从您的视图中选择*,其中一些日期列>%s和一些日期列<%s”
    参数=('foo','bar')
    将connection.cursor()作为cur:
    当前执行(sql,参数)
    data=cur.fetchall()
    
    如果您只需要每个用户和设备的日志计数(这是您从发布的代码中获得的),只需一次查询即可获得:

    from django.db.models import Count
    
    logs = (Log.objects
        .filter(created_at__range = (from_date, to_date))
        .values('user', 'device')
        .annotate(log_count=Count('device'))
    )
    
    您可以修改查询以包括所需的用户和设备型号的任何属性:

    .values('user__last_name', 'device__name')  # etc.
    
    您还可以通过在末尾添加
    order\u by()
    对数据集进行排序,以便能够按所需顺序对其进行迭代:

    .order_by('user__last_name', '-log_count')
    

    你在用什么数据库?@Jane在用MySQL数据库后端你有模型的代码吗?显示模型之间关系的部分模型就足够了。感谢您的详细回答,尤其是在此标准中使用代理模型。但是我的问题是,有没有一种方法可以使用Django ORM的查询方式来避免编写直接的MySQl查询此查询跳过没有日志的设备。但我希望在没有日志时使用0更新日志。提前感谢。这样您就不用再查询
    用户
    (或
    设备
    )型号了。您必须使用三个模型的代码更新问题,以便我们可以考虑查询。您只想要没有日志的设备还是想要没有日志的用户?我想要与用户关联的所有设备日志(计数),而不考虑日志计数(有日志还是没有日志),让用户处于
    值中就可以了。