2017-11-15 3 views
0

postgresテーブルを反復処理すると、わかりにくいオーバーヘッドが発生します。peeweeを使用してpostgresの1k +行を反復処理するときのオーバーヘッド

私はこのコードをプロファイリングし、遅い接続または基礎となるドライバ(psycopg2)でないことを確認するために、SQLAlchemyでスモークテストを行いました。

〜1Mレコードのpostgresテーブルに対してこれを実行しますが、そのほんのわずかな部分しかフェッチしません。

生:制限= 1000で

import time 

import peewee 
import sqlalchemy 
from playhouse import postgres_ext 
from sqlalchemy.dialects.postgresql import JSONB 
from sqlalchemy.engine.url import URL as AlchemyURL 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker as alchemy_sessionmaker 

user = 'XXX' 
password = 'XXX' 
database = 'XXX' 
host = 'XXX' 
port = 5432 

table = 'person' 
limit = 1000 

peewee_db = postgres_ext.PostgresqlExtDatabase(
    database=database, 
    host=host, port=port, 
    user=user, password=password, 
    use_speedups=True, 
    server_side_cursors=True, 
    register_hstore=False, 
) 

alchemy_engine = sqlalchemy.create_engine(AlchemyURL('postgresql', username=user, password=password, 
                database=database, host=host, port=port)) 
alchemy_session = alchemy_sessionmaker(bind=alchemy_engine)() 


class PeeweePerson(peewee.Model): 
    class Meta: 
     database = peewee_db 
     db_table = table 

    id = peewee.CharField(primary_key=True, max_length=64) 
    data = postgres_ext.BinaryJSONField(index=True, index_type='GIN') 


class SQLAlchemyPerson(declarative_base()): 
    __tablename__ = table 

    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 
    data = sqlalchemy.Column(JSONB) 


def run_raw_query(): 
    ids = list(peewee_db.execute_sql(f"SELECT id from {table} order by id desc limit {limit}")) 
    return ids 


def run_peewee_query(): 
    query = PeeweePerson.select(PeeweePerson.id).order_by(PeeweePerson.id.desc()).limit(limit) 
    ids = list(query.tuples()) 
    return ids 


def run_sqlalchemy_query(): 
    query = alchemy_session.query(SQLAlchemyPerson.id).order_by(sqlalchemy.desc(SQLAlchemyPerson.id)).limit(limit) 
    ids = list(query) 
    return ids 


if __name__ == '__main__': 
    t0 = time.time() 
    raw_result = run_raw_query() 
    t1 = time.time() 
    print(f'Raw: {t1 - t0}') 

    t2 = time.time() 
    sqlalchemy_result = run_sqlalchemy_query() 
    t3 = time.time() 
    print(f'SQLAlchemy: {t3 - t2}') 

    t4 = time.time() 
    peewee_result = run_peewee_query() 
    t5 = time.time() 
    print(f'peewee: {t5 - t4}') 

    assert raw_result == sqlalchemy_result == peewee_result 
  • 0.02643609046936035
    SQLAlchemyの:0.03697466850280762
    ピーウィー:制限= 10000

    生で1.0509874820709229

  • :0.15931344032287598
    SQLAlchemyの:0.07229042053222656
    ピーウィー:10.82826042175293

両方の例は、サーバー側カーソルを使用します。

私は簡単にこれをプロファイリングし、時間の95%+のように見えますが、最大cursor.fetchonehttps://github.com/coleifer/peewee/blob/d8e34b0682d87bd56c1a3636445d9c0fccf2b1e2/peewee.py#L2340

任意のアイデアをいただきました!を呼ん費やされていますか?

答えて

1

これは、Peewee 2.xでのサーバー側カーソルの実装の非効率性に関連しているようです。具体的には、peeweeのカーソルラッパーは多くの行をフェッチするのではなく、.fetchone()db-apiを使用するためです。 3.0aには新しい実装が含まれています。https://github.com/coleifer/peewee/commit/0ae17c519475c935d9db3c338f36ef058a3f879c

さらに、2.xでクライアント側のカーソルを使用すると、これらの効率の問題はありませんので、当面の回避策として使用できます。

関連する問題