所以我试图优化一个相当奇怪的查询,但这是一个遗留数据库,所以我做什么我有。这些是我正在尝试的查询。此时它们提供相同的输出。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字典中的addlcomplete和addldate,并在Having子句中使用它们来进一步过滤查询集),但我当然不喜欢它花费的时间。是在模板层慢还是在实际查询层慢?我怎样才能最好地调试它?
感谢您在这种糟糕的数据结构中寻求优化的帮助。
UPDATE 1: 2011-10-03
所以我安装了django-debugtoolbar来窥探一下,我启用了MySQL通用日志记录,并得出以下结论:
using .filter()
或.extra()
查询总数为2。使用.raw()
总查询计数为1984!!(不可忽略的恐怖文学参考)
我的模板正在使用regroup,然后循环遍历该regroup。没有遵循任何关系,没有使用除了内置之外的模板标记。Select_related没有被使用,我仍然只得到2个查询。查看mysql日志,果然是1984查询。
当查看被执行的查询时,基本上看起来像是每个{{ Modelinstance.field }}
django都在做SELECT pk, field FROM Model WHERE Model.pk = Modelinstance.pk
,如果你问我,这似乎是完全错误的。是我在这里错过了什么,还是django真的在查询中乱跑?
END UPDATE 1
更新2 见下面的答案
格雷格好的。以下是我最后的结论。虽然Furbeenator关于Django内部优化是正确的,但事实证明,有一个更大的用户错误导致了速度减慢和前面提到的数千个查询。
在Raw queryset文档中清楚地记录了,当您推迟字段(即不使用SELECT * FROM ...
)并且仅选择特定字段(SELECT Checkin.Sampleid, ...
)时,您不选择的字段仍然可以访问,但使用另一个数据库调用。所以,如果你在你的原始查询中选择了一个字段的子集,而你在你的查询中忘记了一个你在模板中使用的字段,Django会执行数据库查找来找到你在模板中引用的字段,而不是抱怨它不存在或其他什么。所以,假设你从你的查询(这就是我所做的)中遗漏了5个字段,你最终在模板中引用,你有300条记录,你正在循环。这将导致1500次额外的数据库点击来获取每条记录的5个字段。
在优化部分:数据库访问优化中,他们提出了优化的方法,其中之一是extra()方法。然后他们提到了.raw()。我的假设是,他们使raw()更加健壮和强大,因此它提供了最大的优化灵活性。执行原始SQL查询允许您执行比extra()更多的操作。我的直觉是,它只是更注重灵活性而不是性能,在可能的情况下,应该使用extra()而不是raw()。