2017-06-01 15 views
0

私はデータベースパフォーマンスsqlalchemyの及び又は

q = session.query(hd_tbl).\ 
    join(dt_tbl, hd_tbl.c['data_type'] == dt_tbl.c['ID']).\ 
    filter(or_(and_(hd_tbl.c['object_id'] == get_id(row['object']), 
        hd_tbl.c['data_type'] == get_id(row['type']), 
        hd_tbl.c['data_provider'] == get_id(row['provider']), 
        hd_tbl.c['data_account'] == get_id(row['account'])) 
      for index, row in data.iterrows())).\ 
    with_entities(hd_tbl.c['ID'], hd_tbl.c['object_id'], 
        hd_tbl.c['data_type'], hd_tbl.c['data_provider'], 
        hd_tbl.c['data_account'], dt_tbl.c['value_type']) 
hd_tbldt_tblがSQL DB内の2つのテーブルがあり

、及びdataからいくつかのデータを取得するために、次のSQLAlchemyのコードを使用すると、典型的には約1K-9Kエントリを含むパンダのデータフレームであります。 hd_tblには、現在約90k行が含まれています。

実行時間は、dataの長さで指数関数的に増加するようです。

SELECT data_header.`ID`, data_header.object_id, data_header.data_type, data_header.data_provider, data_header.data_account, basedata_data_type.value_type 
FROM data_header INNER JOIN basedata_data_type ON data_header.data_type = basedata_data_type.`ID` 
WHERE data_header.object_id = %s AND data_header.data_type = %s AND data_header.data_provider = %s AND data_header.data_account = %s OR 
data_header.object_id = %s AND data_header.data_type = %s AND data_header.data_provider = %s AND data_header.data_account = %s OR 
... 
data_header.object_id = %s AND data_header.data_type = %s AND data_header.data_provider = %s AND data_header.data_account = %s OR 

テーブルと列が完全にインデックス化され、パフォーマンスが満足ではありません。次のように(SQLAlchemyの別)、対応するSQLステートメントが見えます。現在、hd_tbldt_tblのすべてのデータをメモリに読み込んで、pandas merge機能とマージするのは簡単です。しかし、これは最適ではないようです。誰でも、どのようにsqlalchemy呼び出しを改善するためのアイデアを持っている?

EDIT: 私は次のようにSQLAlchemyのtuple_を使用してsignifcantlyパフォーマンスを向上させることができました:私はあなたが作成をお勧めしたい...

SELECT data_header.`ID`, data_header.object_id, data_header.data_type, data_header.data_provider, data_header.data_account, basedata_data_type.value_type 
FROM data_header INNER JOIN basedata_data_type ON data_header.data_type = basedata_data_type.`ID` 
WHERE (data_header.object_id, data_header.data_type, data_header.data_provider, data_header.data_account) IN ((%(param_1)s, %(param_2)s, %(param_3)s, %(param_4)s), (%(param_5)s, ...)) 
+0

もちろん、それは遅くなるでしょう。テーブルの1つをループし、何千もの条件を持つ巨大なWHERE句を構築することによって 'JOIN'をやっています。データフレームから一時テーブルを作成し、適切な 'JOIN'を実行する必要があります。 – univerio

答えて

1

対応するクエリと

header_tuples = [tuple([int(y) for y in tuple(x)]) for x in 
       data_as_int.values] 
q = session.query(hd_tbl). \ 
    join(dt_tbl, hd_tbl.c['data_type'] == dt_tbl.c['ID']). \ 
    filter(tuple_(hd_tbl.c['object_id'], hd_tbl.c['data_type'], 
        hd_tbl.c['data_provider'], 
        hd_tbl.c['data_account']).in_(header_tuples)). \ 
    with_entities(hd_tbl.c['ID'], hd_tbl.c['object_id'], 
        hd_tbl.c['data_type'], hd_tbl.c['data_provider'], 
        hd_tbl.c['data_account'], dt_tbl.c['value_type']) 

フィールド上のコンポジットインデックスobject_iddata_typedata_provider...は同じ順序で、テーブルに配置されており、それらが同じWHERE条件で注文してください。それはディスク容量のコストであなたの要求を少しスピードアップするかもしれません。

複雑なOR条件の大きなクエリではなく、結果としていくつかの小さなSQL要求を使用することもできます。アプリケーション側で抽出されたデータを累積するか、量が十分な場合は高速な一時ストレージ(テンポラリテーブル、noSQLなど)に蓄積する

さらに、MySQLの設定を確認し、スレッド、リクエストなどです。良い考えは、コンポジットインデックスが使用可能なメモリに収まるかどうかをチェックすることです。そうしないと、無駄です。

私はDBチューニングが生産性を向上させるのに役立つかもしれないと思います。それ以外の場合は、アプリケーションのアーキテクチャを分析してより重要な結果を得ることができます。

関連する問題