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

此代码甚至没有获取一大块轨道标签就会产生以下错误:

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而同时运行两个查询的情况。根据您调用函数的方式(线程、异步等),我很确定您的光标也可能会被破坏?

同样,通过基本上使用 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

一件事也让我很生气-您定义了trackTags = {},但随后您更新了tagTrackIds,并产生了trackTags ..这将始终是空字典。

我的建议是,如果你只是想让一个爱好项目工作,就不要为手写 SQL 的头痛而烦恼。看看建立在SQLAlchemy之上的Elixir

使用 ORM(对象关系映射器)可以更友好地介绍数据库。定义你的对象在 Python 中的样子,并让它自动为你生成你的模式——并且能够以 Python 的方式添加/修改/删除东西真的很漂亮。

如果您真的需要异步,请查看ultramysql python 模块。

于 2012-11-12T12:56:42.040 回答
1

您使用SSDictCursor, 映射到mysql_use_result()MySQL-API 端的东西。这要求您在发出新命令之前读出完整的结果。

因为这发生在你收到第一块数据之前:你确定这不会在执行这部分代码之前的查询上下文中发生吗?最后一个查询的结果可能仍在行中,执行下一个查询(即,在上下文中的第一个查询)可能会破坏事情......

于 2012-11-12T13:37:30.100 回答