LoginSignup
14
16

More than 5 years have passed since last update.

SQLAlchemy ORM でクエリ生成の高速化

Last updated at Posted at 2012-08-22

次のようなテーブルがあったとします。

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base

base = declarative_base()

class Xyz(base):
    __tablename__ = 'xyz'
    id = sa.Column(sa.INTEGER, primary_key=True)
    c1 = sa.Column(sa.INTEGER)
    c2 = sa.Column(sa.INTEGER)
    c3 = sa.Column(sa.INTEGER)
    c4 = sa.Column(sa.INTEGER)
    c5 = sa.Column(sa.INTEGER)
    c6 = sa.Column(sa.INTEGER)
    c7 = sa.Column(sa.INTEGER)
    c8 = sa.Column(sa.INTEGER)
    c9 = sa.Column(sa.INTEGER)

    @classmethod
    def from_c3(cls, n):
        return session.query(cls).filter_by(c3=n).one()

この from_c3() が時間がかかっている場合、ORMがSQLを生成するのにかかっている時間は次のようにして調べられます。

from sqlalchemy.orm import Query
from timeit import timeit

f1 = lambda: str(Query(Xyz).filter_by(c3=123))
print f1()
print timeit(f1, number=10000)

'''結果
SELECT xyz.id AS xyz_id, xyz.c1 AS xyz_c1, xyz.c2 AS xyz_c2, xyz.c3 AS xyz_c3, xyz.c4 AS xyz_c4, xyz.c5 AS xyz_c5, xyz.c6 AS xyz_c6, xyz.c7 AS xyz_c7, xyz.c8 AS xyz_c8, xyz.c9 AS xyz_c9 
FROM xyz 
WHERE xyz.c3 = :c3_1
4.91327404976
'''

これに時間がかかっている場合は、生成したSQLをキャッシュすることでクエリを高速化することができます。

compiled = str(Query(Xyz).filter_by(c3=sa.bindparam('c3')))
f2 = lambda: str(Query(Xyz).from_statement(compiled).params(c3=123))
print f2()
print timeit(f2, number=10000)

'''結果
SELECT xyz.id AS xyz_id, xyz.c1 AS xyz_c1, xyz.c2 AS xyz_c2, xyz.c3 AS xyz_c3, xyz.c4 AS xyz_c4, xyz.c5 AS xyz_c5, xyz.c6 AS xyz_c6, xyz.c7 AS xyz_c7, xyz.c8 AS xyz_c8, xyz.c9 AS xyz_c9 
FROM xyz 
WHERE xyz.c3 = :c3
1.09750509262
'''

このSQL生成時間はスキーマの複雑さに依存するので、もっとカラム数が多いテーブルではもっと時間を節約できます。

追記

filter_by(c3=sa.bindparam('c3') よりも filter('c3=:c3') の方がお手軽ですね。

14
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
16