sql >> データベース >  >> RDS >> Mysql

ORMを介したSQLAlchemyオブジェクトのロードが、生のMySQLdbカーソルを介した行よりも5〜8倍遅いのはなぜですか?

    MySQLdbの3つと比較して、4秒で実行されるMySQLスクリプトのSQLAlchemyバージョンは次のとおりです。

    from sqlalchemy import Integer, Column, create_engine, MetaData, Table
    import datetime
    
    metadata = MetaData()
    
    foo = Table(
        'foo', metadata,
        Column('id', Integer, primary_key=True),
        Column('a', Integer(), nullable=False),
        Column('b', Integer(), nullable=False),
        Column('c', Integer(), nullable=False),
    )
    
    
    class Foo(object):
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
    
    engine = create_engine('mysql+mysqldb://scott:[email protected]/test', echo=True)
    start = datetime.datetime.now()
    
    with engine.connect() as conn:
        foos = [
            Foo(row['a'], row['b'], row['c'])
            for row in
            conn.execute(foo.select().limit(1000000)).fetchall()
        ]
    
    
    print "total time: ", datetime.datetime.now() - start
    

    ランタイム:

    total time:  0:00:04.706010
    

    これは、ORMを使用してオブジェクト行を完全にロードするスクリプトです。イールドパーを使用して一度にすべての100万オブジェクトで固定リストを作成することを回避することにより、これは13秒で実行されます。 SQLAlchemyマスターを使用(rel 0.9で18秒):

    import time
    from sqlalchemy import Integer, Column, create_engine, Table
    from sqlalchemy.orm import Session
    from sqlalchemy.ext.declarative import declarative_base
    
    Base = declarative_base()
    
    
    class Foo(Base):
        __table__ = Table(
            'foo', Base.metadata,
            Column('id', Integer, primary_key=True),
            Column('a', Integer(), nullable=False),
            Column('b', Integer(), nullable=False),
            Column('c', Integer(), nullable=False),
        )
    
    
    engine = create_engine('mysql+mysqldb://scott:[email protected]/test', echo=True)
    
    sess = Session(engine)
    
    now = time.time()
    
    # avoid using all() so that we don't have the overhead of building
    # a large list of full objects in memory
    for obj in sess.query(Foo).yield_per(100).limit(1000000):
        pass
    
    print("Total time: %d" % (time.time() - now))
    

    次に、これら2つのアプローチの違いを分割し、ORMを使用して個々の列のみをロードできます。

    for obj in sess.query(Foo.id, Foo.a, Foo.b, Foo.c).yield_per(100).limit(1000000):
        pass
    

    上記は再び4秒で実行されます 。

    SQLAlchemy Coreの比較は、生のMySQLdbカーソルとのより適切な比較です。 ORMを使用しているが、個々の列をクエリする場合、最新バージョンでは約4秒です。

    ORMレベルでは、速度の問題はPythonでのオブジェクトの作成が遅いためです。また、SQLAlchemy ORMは、オブジェクトをフェッチするときにこれらのオブジェクトに大量の簿記を適用します。これは、ユニットを含む使用契約を履行するために必要です。仕事の、アイデンティティマップ、熱心な読み込み、コレクションなど。

    クエリを劇的に高速化するには、完全なオブジェクトではなく、個々の列をフェッチします。 http://docsでテクニックを参照してください.sqlalchemy.org / en / latest / faq / performance.html#result-fetching-slowness-orm これを説明しています。

    PeeWeeと比較すると、PWは、IDマップでは何も実行しないなど、機能がはるかに少ない、はるかに単純なシステムです。 PeeWeeを使用しても、可能な限り単純なORMでも、15秒かかります。 、これはcPythonが本当に遅いという証拠です ストレートCにある生のMySQLdbフェッチと比較してください。

    Javaと比較すると、JavaVMはcPythonよりもはるかに高速です 。 Hibernateはばかげて 複雑ですが、JITのおかげでJava VMは非常に高速であり、その複雑さでさえも実行速度が速くなります。 PythonとJavaを比較する場合は、Pypyを使用してください。



    1. 2つの重複する列を削除する方法

    2. PostgreSQLWhereカウント条件

    3. ASP、MySQL、UTF-8

    4. MYSQL CONCAT MAX LENGTH