1. ホーム
  2. mysql

[解決済み] なぜ SQLAlchemy の count() は生のクエリよりずっと遅いのでしょうか?

2022-03-13 03:10:33

質問

MySQLデータベースでSQLAlchemyを使っていますが、あるテーブルの行数を数えたいと思っています(およそ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() は、トリックを実行し、スピードアップするようです。しかし、なぜ最初のクエリーが遅くなるのか、まだ不可解です。

解決方法は?

残念ながら 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

カウントするカラムを細かく制御したい場合。 サブクエリの使用や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)))