2

次のコードがあります。

def executeQuery(conn, query):
    cur = conn.cursor()
    cur.execute(query)
    return cur

def trackTagsGenerator(chunkSize, baseCondition):
    """ Returns a dict of trackId:tag limited to chunkSize. """

    sql = """
        SELECT track_id, tag
        FROM tags 
        WHERE {baseCondition}
    """.format(baseCondition=baseCondition)

    limit = chunkSize
    offset = 0
    while True:
        trackTags = {}

        # fetch the track ids with the coresponding tag
        limitPhrase = " LIMIT %d OFFSET %d" % (limit, offset)
        query = sql + limitPhrase
        offset += limit
        cur = executeQuery(smacConn, query)
        rows = cur.fetchall()

        if not rows:
            break

        for row in rows:
            trackTags[row['track_id']] = row['tag']

        yield trackTags

私はそれを次のように使いたいです:

for trackTags in list(trackTagsGenerator(DATA_CHUNK_SIZE, baseCondition)):        
    print trackTags
    break

このコードは、トラック タグの 1 つのチャンクをフェッチすることさえせずに、次のエラーを生成します。

Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") in <bound method SSDictCursor.__del__ of <MySQLdb.cursors.SSDictCursor object at 0x10b067b90>> ignored

ジェネレーター関数のループ本体にクエリ実行ロジックがあるためだと思います。

そのような方法で mysqldb を使用してデータのチャンクをフェッチする方法を教えてくれる人はいますか?

4

2 に答える 2

1

これは、 yieldが原因で 2 つのクエリが同時に実行される状況に陥る可能性があるためだと確信しています。関数の呼び出し方法 (スレッド、非同期など) によっては、カーソルも破壊される可能性があると確信していますか?

また、基本的に printf を使用して baseConditional を挿入することで、(申し訳ありませんが、この部分をシュガー コートすることはできません) 恐ろしい SQL インジェクション ホールに自分自身を開いてしまいます。ヘルプについては、DB-API のパラメーター置換ドキュメントを参照してください。

ここでは、Yield によって時間やエネルギーがまったく節約されるわけではありません。単一の結果を取得する前に、常に完全な sql コマンドを実行する必要があります。(したがって、より使いやすくするために LIMIT と OFFSET を使用しています、称賛)

つまり、この特定のケースでは、世界の終わりではなく、データを生成している間に誰かがテーブルを更新します。他の多くの場合、それは醜くなります。

あなたがただふざけていて、これを「すぐに」機能させたい場合は、おそらく executeQuery を次のように変更すると機能するでしょう。

 def executeQuery(conn, query):
     cur = conn.cursor()
     cur.execute(query)
     cur = executeQuery(smacConn, query)
     rows = cur.fetchall()
     cur.close()
     return rows

また、ちょっと気になる点が 1 つあります。trackTags = {} を定義しますが、tagTrackIds を更新すると trackTags が生成されます。これは常に空の dict になります。

私の提案は、趣味のプロジェクトを機能させようとしているだけの場合は、SQL を手書きするという頭痛の種に悩まされないことです。SQLAlchemyの上に構築されたElixirを見てみましょう。

ORM (object-relational-mapper) を使用すると、データベースへの導入がより簡単になります。Python でオブジェクトがどのように見えるかを定義し、スキーマを自動的に生成するようにし、Python の方法で物事を追加/変更/削除できることは、本当に気の利いたことです。

本当に非同期にする必要がある場合は、ultramysql python モジュールを確認してください。

于 2012-11-12T12:56:42.040 に答える
1

、MySQL-API側にSSDictCursorマップするものを使用します。mysql_use_result()これには、新しいコマンドを発行する前に、完全な結果を読み取る必要があります。

結局のところ、これはデータの最初のチャンクを受け取る前に発生するため、コードのこの部分が実行される前にクエリのコンテキストでこれが発生しないと確信していますか? その最後のクエリの結果がまだ行にある可能性があり、次のクエリ (つまり、このコンテキストでは最初のクエリ) を実行すると、問題が発生する可能性があります...

于 2012-11-12T13:37:30.100 に答える