Django:为什么 Foo.objects.extra(...) 比 Foo.objects.raw 快得多?

标签 django django-models django-templates query-optimization django-queryset

所以我试图优化一个相当奇怪的查询,但这是一个遗留数据库,所以我只能用我现有的。这些是我正在尝试的查询。在这一点上,它们提供相同的输出。 w 是我的查询集。

def future_schedule(request):

    past = datetime.date.today()-datetime.timedelta(days=730)

    extra_select = {
        'addlcomplete': 'SELECT Complete FROM tblAdditionalDates WHERE Checkin.ShortSampleID = tblAdditionalDates.ShortSampleID',
        'addldate': 'SELECT AddlDate FROM tblAdditionalDates WHERE Checkin.ShortSampleID = tblAdditionalDates.ShortSampleID'
    }
    extra_where = ['''(Checkin.Description <> "Sterilization Permit" AND Checkin.Description <> "Registration State" AND Checkin.Description <> "Miscellaneous" AND Checkin.Description <> "Equipment Purchase" AND Checkin.DateArrived > %s AND Checkin.DateCompleted IS NULL AND Checkin.Canceled = 0) OR (Checkin.Description <> "Sterilization Permit" AND Checkin.Description <> "Registration State" AND Checkin.Description <> "Miscellaneous" AND Checkin.Description <> "Equipment Purchase" AND Checkin.DateArrived > %s AND Checkin.DateCompleted IS NOT NULL AND Checkin.DateFinalCompleted IS NULL AND Checkin.DateFinalExpected IS NOT NULL AND Checkin.Canceled = 0) '''
    ]
    extra_params = [past, past]

    w = Checkin.objects.extra(select=extra_select, where=extra_where, params=extra_params)

# OR This one

    w = Checkin.objects.raw('''SELECT Checkin.SampleID, Checkin.ShortSampleID, Checkin.Company, A.Complete, Checkin.HasDates, A.AddlDate FROM Checkin LEFT JOIN (SELECT ShortSampleID, Complete, AddlDate FROM tblAdditionalDates) A ON A.ShortSampleID = Checkin.ShortSampleID WHERE (Checkin.Description <> "Sterilization Permit" AND Checkin.Description <> "Registration State" AND Checkin.Description <> "Miscellaneous" AND Checkin.Description <> "Equipment Purchase" AND Checkin.DateArrived > "2009-01-01" AND Checkin.DateCompleted IS NULL AND Checkin.Canceled = 0) OR (Checkin.Description <> "Sterilization Permit" AND Checkin.Description <> "Registration State" AND Checkin.Description <> "Miscellaneous" AND Checkin.Description <> "Equipment Purchase" AND Checkin.DateArrived > "2009-01-01" AND Checkin.DateCompleted IS NOT NULL AND Checkin.DateFinalCompleted IS NULL AND Checkin.DateFinalExpected IS NOT NULL AND Checkin.Canceled = 0)''')

这两者都返回相同数量的记录 (322)。 .extra 呈现 HTML 的速度比 .raw 查询快 10 秒左右,对于所有密集型目的,.raw 查询甚至稍微不那么复杂。有没有人知道为什么会这样?根据我的结构,.raw 可能是我获取所需数据的唯一方法(我需要在 extra_select dict 中使用 addlcomplete 和 addldate 并在 Have 子句中使用它们来进一步过滤查询集)但我当然不喜欢如何它需要很长时间。是在模板层上速度较慢还是实际查询层?我怎样才能最好地调试这个?

感谢您在糟糕的数据结构中寻求优化的帮助。

更新 1:2011-10-03

所以我安装了 django-debugtoolbar 来窥探一下,我启用了 MySQL 常规日志记录并提出了以下内容:

使用 .filter().extra()查询总数为 2。使用 .raw()查询总数为 1984!!! (幽灵般的文学引用不被忽视)

我的模板正在使用重组,然后循环遍历重组。没有遵循任何关系,没有使用除内置之外的模板标签。 Select_related 没有被使用,我仍然只得到 2 个查询。查看mysql日志,果然——1984查询。

查看执行的查询时,基本上每个 {{ Modelinstance.field }} 都是这样的。 django 正在做一个 SELECT pk, field FROM Model WHERE Model.pk = Modelinstance.pk如果你问我,这似乎完全错误。我在这里遗漏了什么还是 django 真的在查询中狂奔?

结束更新 1

更新 2
请参阅下面的答案

格雷格

最佳答案

好的。这是我的最终结论。虽然 Furbeenator 关于内部 Django 优化是正确的,但事实证明存在更大的用户错误导致速度变慢和上述数千个查询。

Raw queryset docs 中清楚地记录了这一点。当您推迟字段(即不使用 SELECT * FROM ... )并且只选择特定的字段时( SELECT Checkin.Sampleid, ... 您未选择的字段仍然可以访问,但需要另一个数据库调用。因此,如果您选择一个子集原始查询中的字段,而您忘记了在模板中使用的查询中的字段,Django 执行数据库查找以找到您在模板中引用的字段,而不是提示它不存在或其他什么。所以,让我们说你从你的查询中遗漏了 5 个字段(这就是我所做的),你最终在你的模板中引用了 300 条记录,你正在循环。这会导致 1500 次额外的数据库点击来获取每条记录的这 5 个字段。

因此,请注意隐藏的引用并感谢上帝 Django Debug Toolbar

关于Django:为什么 Foo.objects.extra(...) 比 Foo.objects.raw 快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7636859/

相关文章:

javascript - AngularJS:ng-repeat不显示项目

python - 在 django 模型中存储云文件链接列表的最佳方式是什么

python - 在for循环中更改django表单的ID

python - Django_tables2 : Add an edit and delete button next to each row

python - Django REST 框架;使用 'groups' 字段序列化用户模型时出现问题

python - Django Celery 收到类型为 'appname.tasks.add' 的未注册任务

python - 直接在Models中存储django forms.MultipleChoiceField

django - 在 Django 中,您不能在 ManyToManyField 上使用字符串连接吗? ManyToMany 不只是一个列表吗?

Django:在模板中分配变量

Django url 模板标签给出 NoReverseMatch 错误