Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 针对3个相关表的Django查询优化_Python_Django_Postgresql_Django Queryset - Fatal编程技术网

Python 针对3个相关表的Django查询优化

Python 针对3个相关表的Django查询优化,python,django,postgresql,django-queryset,Python,Django,Postgresql,Django Queryset,我有4种型号: class Run(models.Model): start_time = models.DateTimeField(db_index=True) end_time = models.DateTimeField() chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE) recipe = models.ForeignKey(Recipe, default=None, blank=

我有4种型号:

class Run(models.Model):
    start_time = models.DateTimeField(db_index=True)
    end_time = models.DateTimeField()
    chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
    recipe = models.ForeignKey(Recipe, default=None, blank=True, null=True, on_delete=models.CASCADE)

class RunProperty(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE)
    property_name = models.CharField(max_length=50)
    property_value = models.CharField(max_length=500)

class RunValue(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE)
    run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
    value = models.FloatField(default=0)

class RunParameter(models.Model):
    parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)
    chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
    param_name_user_defined = models.BooleanField(default=True)
Run
可以有任意数量的
RunProperty
(通常是用户定义的属性,可以自定义),以及一些预定义的
RunValue
(例如平均电压、最小电压、最大电压)为数值

RunParameter
基本上只是一个参数名称(电压、电流、频率、温度、阻抗、振荡、可变性等)的容器,有很多

当我构建前端表以显示每个
运行
及其所有“文件”
RunProperty
(运行的来源)和所有“电压”时
RunValue
,我首先查询数据库中的所有
Run
对象,然后再查询3次Min/Max/Avg,然后再查询一次文件,然后在后端构建一个dict传递到前端以构建表行:

runs = Run.objects.filter(chamber__in=chambers)
min_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Minimum Voltage")
max_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Maximum Voltage")
avg_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Average Voltage")
run_files = RunProperty.objects.filter(run__in=runs, property_name="File")
对于数据库中有10到30个
Run
对象的客户来说,这并不是什么大问题,但我们有一个使用率很高的客户,他有3500个
Run
实例。不用说,速度太慢了。我正在进行5次查询,以获得所有需要的实例,然后我必须循环并将它们放在一个目录中。这需要我们为一个客户执行此操作需要45秒的时间(大多数其他客户大约需要8秒或10秒)

有没有一种方法可以让我查询数据库中的所有
Run
对象,以及所有的最小/最大/平均电压
RunValue
和文件
RunProperty
,然后返回一个dict列表,每个
Run
和其他对象对应一个dict

我认为这里可以使用
Q
查询,但我不太确定如何使用它们,或者它们是否适用于此场景

我试过这个(但没有成功):

这让我在一个查询中获得所有与
RunValue
相关的对象,但每个查询仍然有3个。如果可能的话,我需要对此进行更多优化

我正在寻找以下内容:

runs = Run.objects.filter(chamber__in=chambers)
        .annotate(Q(run__runvalue__run_parameter__parameter__parameter_name__icontains="Voltage")
                & Q(run__runproperty__property_name__icontains="File"))
我认为从广义上讲(甚至不是伪代码),我需要一个如下的查询:

“获取所有
运行
s,对于每个
运行
,获取与该
运行
相关的包含[“平均”、“最大”、“最小”]的所有
运行
对象,以及该
运行
包含“文件”的所有
运行属性
对象。”

我不知道这是否可能(听起来应该是这样),我也不确定是否应该使用Q过滤、聚合或注释。概括地说,如果可能的话,我需要在一个查询中获得一个模型的所有实例,以及每个实例的所有外键

例如:

我有表
运行
,有两个实例:

R1
R2
每个
Run
实例都有一个关联的RunProperty实例“文件”(仅一个字符串),用于:

R1_run.dat
R2_run.dat
每个
Run
实例都有许多RunValue实例(我使用Voltage作为示例,但有26个):

我需要查询数据库,以便它返回(list或dict,我可以解决这两种情况之一):

甚至是二维阵列:

[[R1, R1_run.dat, R1_max_v, R1_min_v, R1_avg_v],
[R2, R2_run.dat, R2_max_v, R2_min_v, R2_avg_v]]

这可能吗?

从数据库的角度来看,只需使用一个查询和几个连接即可获得所需的所有数据:

-- This assumes that there is a primary key Run.id and 
-- foreign keys RunValue.run_id and RunProperty.run_id.
-- IDs or names of min/max/avg run parameters, as well as 
-- chamber ids are replaced with *_PARAMETER and CHAMBER_IDS 
-- for brevity.
SELECT Run.*, 
       RVmin.value AS min_value, 
       RVmax.value AS max_value,
       RVavg.value AS avg_value,
       RP.value AS file_value
FROM Run 
JOIN RunValue RVmin ON Run.id = RVmin.run_id
JOIN RunValue RVmax ON Run.id = RVmax.run_id
JOIN RunValue RVavg ON Run.id = RVavg.run_id
JOIN RunProperty RP ON Run.id = RP.run_id
WHERE
  RVmin.run_parameter = MIN_PARAMETER AND
  RVmax.run_parameter = MAX_PARAMETER AND
  RVavg.run_parameter = AVG_PARAMETER AND
  RP.property_name = 'File' AND
  Run.chamber IN (CHAMBER_IDS);
Django构建这种连接的方法必须类似于
Run.runvalue\u set.filter(Run\u参数\u包含“最大电压”)

请参阅“以下向后关系”:

从数据库的角度来看,只需使用一个查询和几个连接即可获得所需的所有数据:

-- This assumes that there is a primary key Run.id and 
-- foreign keys RunValue.run_id and RunProperty.run_id.
-- IDs or names of min/max/avg run parameters, as well as 
-- chamber ids are replaced with *_PARAMETER and CHAMBER_IDS 
-- for brevity.
SELECT Run.*, 
       RVmin.value AS min_value, 
       RVmax.value AS max_value,
       RVavg.value AS avg_value,
       RP.value AS file_value
FROM Run 
JOIN RunValue RVmin ON Run.id = RVmin.run_id
JOIN RunValue RVmax ON Run.id = RVmax.run_id
JOIN RunValue RVavg ON Run.id = RVavg.run_id
JOIN RunProperty RP ON Run.id = RP.run_id
WHERE
  RVmin.run_parameter = MIN_PARAMETER AND
  RVmax.run_parameter = MAX_PARAMETER AND
  RVavg.run_parameter = AVG_PARAMETER AND
  RP.property_name = 'File' AND
  Run.chamber IN (CHAMBER_IDS);
Django构建这种连接的方法必须类似于
Run.runvalue\u set.filter(Run\u参数\u包含“最大电压”)

请参阅“以下向后关系”:

您可以在查询中使用
注释
最小值
最大值
平均值

为了你的问题,你可以这样做

在ForeignKey字段中添加相关名称

class RunProperty(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE, related_name="run_prop_name")

class RunValue(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE, related_name="run_value_name")
    run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
    value = models.FloatField(default=0)
views.py

from django.db.models import Avg, Max, Min

filt = 'run_value_name__value'
query = Run.objects.annotate(run_avg = Avg(filt), run_max = Max(filt))
您可以获得所有值:

  for i in query:
     print(i.run_avg, i.run_max, i.run_min )
------编辑------------

请检查我是否在RunValue模型中添加了“相关名称”

让我们假设您在运行模型中有两个值

1) 运行1

2) 运行2

在模型运行值中,有6个条目

运行=1,运行参数=“平均值”,值=50

运行=1,运行参数=“最小值”,值=25

运行=1,运行参数=“最大值”,值=75

运行=2,运行参数=“平均值”,值=28

运行=2,运行参数=“最大值”,值=40

运行=2,运行参数=“最小值”,值=16

您需要这样的词典:

{'run_1': {'Avg_value': 50, 'Min_value': 25, 'Max_value': 75}, 'run_2': {...}}
要执行此操作,请记住阅读文档的
选择与_相关的
预取与_相关的

    rt = Rub.objects.all().prefetch_related('run_value_name')
    s = {} # output dictionary
    for i in rt:
        s[i.run] = {} # run dictionary
        for j in i.run_value_name.all():

            s[i.run].update({j.run_parameter: j.value}) # update run dictionary

    print(s)
------添加------------

检查此代码命中的数据库数

from django.db import connection, reset_queries
print(len(connection.queries))
reset_queries()

通过使用
注释
最小值
最大值
平均值
,您可以在查询中获得此信息

为了你的问题,你可以这样做

在ForeignKey字段中添加相关名称

class RunProperty(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE, related_name="run_prop_name")

class RunValue(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE, related_name="run_value_name")
    run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
    value = models.FloatField(default=0)
views.py

from django.db.models import Avg, Max, Min

filt = 'run_value_name__value'
query = Run.objects.annotate(run_avg = Avg(filt), run_max = Max(filt))
您可以获得所有值:

  for i in query:
     print(i.run_avg, i.run_max, i.run_min )
------编辑------------

请检查我是否在RunValue模型中添加了“相关名称”

让我们假设您在运行模型中有两个值

1) 运行1

2) 运行2

在模型运行值中,有6个条目

运行=1,运行参数=“平均值”,值=50

运行=1,运行参数=“最小值”,值=25

运行=1,运行参数=“最大值”,值=75

运行=2,运行参数=“平均值”,值=28

运行=2,运行参数=“最大值”,值=40

运行=2,运行参数=“最小值”,值=16

您需要这样的词典:

{'run_1': {'Avg_value': 50, 'Min_value': 25, 'Max_value': 75}, 'run_2': {...}}
要执行此操作,请记住阅读文档的
选择与_相关的
预取与_相关的

    rt = Rub.objects.all().prefetch_related('run_value_name')
    s = {} # output dictionary
    for i in rt:
        s[i.run] = {} # run dictionary
        for j in i.run_value_name.all():

            s[i.run].update({j.run_parameter: j.value}) # update run dictionary

    print(s)
------添加------------

检查数据库hi的编号