为什么SQLAlchemy count()比原始查询慢得多?

mtt*_*tth 38 mysql sqlalchemy

我正在使用带有MySQL数据库的SQLAlchemy,我想计算表中的行数(大约300k).SQLAlchemy 计数函数的运行时间大约是在MySQL中直接写入相同查询的50倍.难道我做错了什么?

# this takes over 3 seconds to return
session.query(Segment).count()
Run Code Online (Sandbox Code Playgroud)

然而:

SELECT COUNT(*) FROM segments;
+----------+
| COUNT(*) |
+----------+
|   281992 |
+----------+
1 row in set (0.07 sec)
Run Code Online (Sandbox Code Playgroud)

速度的差异随着桌子的大小而增加(在100k行下几乎不可察觉).

更新

使用session.query(Segment.id).count()而不是session.query(Segment).count()似乎做的伎俩,让它加快速度.我仍然感到困惑,为什么初始查询速度较慢.

zzz*_*eek 60

不幸的是,MySQL对子查询的支持非常可怕,这对我们的影响很大.在SQLAlchemy的文档指出,"优化"查询可以使用实现query(func.count(Segment.id)):

返回此Query将返回的行数.

这将为此Query生成SQL,如下所示:

SELECT count(1) AS count_1 FROM (
     SELECT <rest of query follows...> ) AS anon_1
Run Code Online (Sandbox Code Playgroud)

要对要计数的特定列进行细粒度控制,跳过子查询的使用或以其他方式控制FROM子句,或使用其他聚合函数,请将func表达式与query()结合使用,即:

from sqlalchemy import func

# count User records, without
# using a subquery.
session.query(func.count(User.id))

# return count of user "id" grouped
# by "name"
session.query(func.count(User.id)).\
        group_by(User.name)

from sqlalchemy import distinct

# count distinct "name" values
session.query(func.count(distinct(User.name)))
Run Code Online (Sandbox Code Playgroud)

  • session.query(func.count(Table.id)).scalar()将为您提供第一行的第一个col. (5认同)
  • 是的,你可以说'self.relationship.with_entities(func.count(User.id)).scalar()`. (2认同)

aeb*_*eb0 11

原因是 SQLAlchemy 的 count() 正在计算子查询的结果,该子查询仍在执行全部工作来检索您正在计算的行。这种行为与底层数据库无关;这不是 MySQL 的问题。

SQLAlchemy文档解释了如何通过funcsqlalchemy.

session.query(func.count(User.id)).scalar()

>>>SELECT count(users.id) AS count_1 \nFROM users')
Run Code Online (Sandbox Code Playgroud)


Jer*_* K. 5

我花了很长时间才找到解决方案来解决我的问题。我收到以下错误:

sqlalchemy.exc.DatabaseError:(mysql.connector.errors.DatabaseError)126(HY000):表'/tmp/#sql_40ab_0.MYI'的密钥文件不正确; 尝试修复它

当我更改此问题时,该问题已解决:

query = session.query(rumorClass).filter(rumorClass.exchangeDataState == state)
return query.count()
Run Code Online (Sandbox Code Playgroud)

对此:

query = session.query(func.count(rumorClass.id)).filter(rumorClass.exchangeDataState == state)
return query.scalar()
Run Code Online (Sandbox Code Playgroud)

  • 这与问题有什么关系?如果引发错误,则情况看起来与OP所描述的完全不同 (3认同)