我有一个名为 Valor 的模型。Valor 有一个机器人。我这样查询:
Valor.objects.filter(robot=r).reverse()[0]
获得最后的Valor the r机器人。Valor.objects.filter(robot=r).count() 大约是 200000,在我的 PC 中获取最后一个项目大约需要 4 秒。
我怎样才能加快速度?我查询的方式不对?
我有一个名为 Valor 的模型。Valor 有一个机器人。我这样查询:
Valor.objects.filter(robot=r).reverse()[0]
获得最后的Valor the r机器人。Valor.objects.filter(robot=r).count() 大约是 200000,在我的 PC 中获取最后一个项目大约需要 4 秒。
我怎样才能加快速度?我查询的方式不对?
此问题的最佳 mysql 语法将类似于以下内容:
SELECT * FROM table WHERE x=y ORDER BY z DESC LIMIT 1
与此等效的 django 将是:
Valor.objects.filter(robot=r).order_by('-id')[:1][0]
请注意此解决方案如何在编译对象列表之前利用 django 的切片方法来限制查询集。
如果之前的建议都不起作用,我建议将 Django 排除在外,并针对您的数据库运行此原始 sql。我猜你的表名,所以你可能需要相应地调整:
SELECT * FROM valor v WHERE v.robot_id = [robot_id] ORDER BY id DESC LIMIT 1;
这么慢吗?如果是这样,请让您的 RDBMS(MySQL?)向您解释查询计划。这将告诉您它是否正在执行任何全表扫描,您显然不希望使用那么大的表。您也可以编辑您的问题并包含valor
表格的架构供我们查看。
此外,您可以看到 Django 通过执行此操作生成的 SQL(使用 Peter Rowell 提供的查询集):
qs = Valor.objects.filter(robot=r).order_by('-id')[0]
print qs.query
确保 SQL 类似于我在上面发布的“原始”查询。您还可以让您的 RDBMS 向您解释该查询计划。
听起来您的数据集将足够大,您可能想要对事物进行一些非规范化。您是否尝试过跟踪 Robot 对象中的最后一个 Valor 对象?
class Robot(models.Model):
# ...
last_valor = models.ForeignKey('Valor', null=True, blank=True)
from django.db.models.signals import post_save
def record_last_valor(sender, **kwargs):
if kwargs.get('created', False):
instance = kwargs.get('instance')
instance.robot.last_valor = instance
post_save.connect(record_last_valor, sender=Valor)
创建 Valor 对象时,您将支付额外的 db 事务的成本,但 last_valor 查找速度会非常快。试一试,看看这个折衷对您的应用程序是否值得。
好吧,没有 order_by 子句,所以我想知道您所说的“最后一个”是什么意思。假设您的意思是“最后添加”,
Valor.objects.filter(robot=r).order_by('-id')[0]
可能会为您完成这项工作。
django 1.6 引入了 .first() 和 .last():
https://docs.djangoproject.com/en/1.6/ref/models/querysets/#last
所以你可以简单地做:
Valor.objects.filter(robot=r).last()
相当快也应该是:
qs = Valor.objects.filter(robot=r) # <-- it doesn't hit the database
count = qs.count() # <-- first hit the database, compute a count
last_item = qs[ count-1 ] # <-- second hit the database, get specified rownum
因此,实际上您只执行 2 个 SQL 查询;)
django中有限制条款吗?这样您就可以拥有数据库,只需返回一条记录。
mysql
select * from table where x = y limit 1
sql服务器
select top 1 * from table where x = y
甲骨文
select * from table where x = y and rownum = 1
我意识到这没有翻译成 django,但有人可以回来清理它。
这样做的正确方法是使用内置的 QuerySet 方法 latest() 并将其提供给它应该排序的任何列(字段名称)。缺点是它只能按单个 db 列排序。
当前的实现看起来像这样,并且在与@Aaron 的建议相同的意义上进行了优化。
def latest(self, field_name=None):
"""
Returns the latest object, according to the model's 'get_latest_by'
option or optional given field_name.
"""
latest_by = field_name or self.model._meta.get_latest_by
assert bool(latest_by), "latest() requires either a field_name parameter or 'get_latest_by' in the model"
assert self.query.can_filter(), \
"Cannot change a query once a slice has been taken."
obj = self._clone()
obj.query.set_limits(high=1)
obj.query.clear_ordering()
obj.query.add_ordering('-%s' % latest_by)
return obj.get()
Model_Name.objects.first()
//获取第一个元素
Model_name.objects.last()
//获取最后一个()
在我的情况下,最后一个不起作用,因为数据库中只有一行可能对你也有帮助:)