57

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

# this takes over 3 seconds to return
session.query(Segment).count()

然而:

SELECT COUNT(*) FROM segments;
+----------+
| COUNT(*) |
+----------+
|   281992 |
+----------+
1 row in set (0.07 sec)

速度差异随着表的大小而增加(在 100k 行下几乎看不到)。

更新

使用session.query(Segment.id).count()而不是session.query(Segment).count()似乎可以解决问题并使其加快速度。我仍然很困惑为什么初始查询速度较慢。

4

3 回答 3

85

不幸的是,MySQL 对子查询的支持非常糟糕,这对我们产生了非常负面的影响。SQLAlchemy 文档指出可以使用以下方法实现“优化”查询query(func.count(Segment.id))

返回此查询将返回的行数。

这会为此查询生成 SQL,如下所示:

SELECT count(1) AS count_1 FROM (
     SELECT <rest of query follows...> ) AS anon_1

要对要计数的特定列进行细粒度控制,跳过子查询的使用或 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)))
于 2013-02-07T18:23:14.760 回答
14

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

SQLAlchemy文档func解释了如何通过导入from来发出没有​​子查询的计数sqlalchemy

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

>>>SELECT count(users.id) AS count_1 \nFROM users')
于 2017-12-13T20:38:15.010 回答
7

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

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()

对此:

query = session.query(func.count(rumorClass.id)).filter(rumorClass.exchangeDataState == state)
return query.scalar()
于 2016-03-18T18:47:58.370 回答