我有三个桌子
我想根据设备和日志过滤日志。我正在使用以下查询,该查询遍历用户和设备以获取日志。我觉得这会成为性能上的打击。如何减少数据库命中次数?
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()
答案 0 :(得分:1)
我要做的是在您的MySQL实例中创建一个引用view
的“代理模型”
视图如下:
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);
现在要创建代理模型,请执行以下操作:
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
现在,要访问所需的数据,您将执行以下操作:
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)
注意,如果您要将参数传递给原始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()
答案 1 :(得分:1)
如果您只需要每个用户和设备的日志计数(这是您从发布的代码中获得的计数),则可以在一个查询中获得该计数:
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_by()
来对数据集进行排序,以便能够按所需顺序对其进行迭代:
.order_by('user__last_name', '-log_count')