Django QuerySet与原始查询performan

2024-10-04 05:20:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我注意到使用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

Tags: 对象函数from模型id列表sqldef