我注意到使用django的时间有很大的差异连接.cursor而不是使用模型接口,即使是小的查询集。 我已经使模型接口尽可能的高效,使用值\u列表,这样就不会构建任何对象。下面是测试的两个函数,不要介意西班牙语名称。在
def t3():
q = "select id, numerosDisponibles FROM samibackend_eventoagendado LIMIT 1000"
with connection.cursor() as c:
c.execute(q)
return list(c)
def t4():
return list(EventoAgendado.objects.all().values_list('id','numerosDisponibles')[:1000])
然后使用一个函数来计时(自制时间时钟())
^{pr2}$结果如下: t3和t4分别为0.00180384529631和0.00493390727024
为了确保查询和执行相同的查询:
connection.queries[-2::]
产量:
[
{u'sql': u'select id, numerosDisponibles FROM samibackend_eventoagendado LIMIT 1000', u'time': u'0.002'},
{u'sql': u'SELECT `samiBackend_eventoagendado`.`id`, `samiBackend_eventoagendado`.`numerosDisponibles` FROM `samiBackend_eventoagendado` LIMIT 1000', u'time': u'0.002'}
]
如您所见,两个精确的查询,返回两个精确的列表(执行r1==r2返回True),需要完全不同的计时(查询集越大,差异越大),我知道python很慢,但是django是否在幕后做了那么多工作,使查询变慢? 另外,为了确保,我已经尝试先构建queryset对象(在计时器之外),但是结果是一样的,所以我百分之百确定额外的时间来自于获取和构建结果结构。 我也尝试过在查询的末尾使用iterator()函数,但这都没有帮助。 我知道差别很小,两者执行速度都非常快,但这是用apacheab进行的benchhared,当有1k个并发请求时,这种最小的差异会让您轻松愉快。在
顺便说一下,我使用django1.7.10和mysqlclient作为db连接器。在
编辑:为了比较,同样的测试使用11k的结果查询集,差异变得更大(比第一个慢3倍,比第一个慢2.6倍)
r1 = timeme(t3); r2 = timeme(t4)
0.0149241530889
0.0437563529558
EDIT2:另一个有趣的测试,如果我真的将queryset对象转换为它的实际字符串查询(使用str(查询集.查询)),并在原始查询中使用它,通过使用查询集.查询字符串有时会给我一个实际无效的SQL查询(即,如果queryset对日期值有筛选器,则日期值不会在字符串查询中用“”转义,在使用原始查询执行时会出现sql错误,这是另一个谜)
——编辑3:
通览代码,似乎不同之处在于如何检索结果数据,对于原始查询集,它只是调用iter(self.cursor)
,我相信在使用C实现的连接器时,它将全部用C代码运行(因为iter也是一个内置的),而ValuesListQuerySet实际上是一个python级别的for循环,带有yield tuple(row)语句,会很慢的。我想在这个问题上没有什么可以做的,以获得与原始查询集相同的性能:'(。
如果有人感兴趣,慢循环是这样的:
for row in self.query.get_compiler(self.db).results_iter():
yield tuple(row)
--EDIT 4:我提供了一个非常老套的代码,可以将值列表查询集转换为可用数据发送到原始查询,其性能与运行原始查询相同,我想这是非常糟糕的,只适用于mysql,但是,速度提高非常好,同时允许我保持模型api过滤等。你怎么认为? 这是密码。在
def querysetAsRaw(qs):
q = qs.query.get_compiler(qs.db).as_sql()
with connection.cursor() as c:
c.execute(q[0], q[1])
return c
答案很简单,更新到django1.8或更高版本,它更改了一些性能不再存在此问题的代码。在
相关问题 更多 >
编程相关推荐