python mysqldb несколько соединений - PullRequest
2 голосов
/ 17 мая 2011

Эй, ребята, у меня следующая проблема: 1 процесс выполняет очень большой запрос и записывает результаты в файл, между которыми процесс должен обновить состояние базы данных.

первая мысль: никаких проблем, псевдокод:

db = mysqldb.connect()
cursor = db.cursor()
large = cursor.execute(SELECT * FROM VERYLARGETABLE)
for result in large.fetchall():
     file.write(result)
if timetoUpdateStatus: cursor.execute(UPDATE STATUS)

проблема: при получении 9 миллионов результатов "large = cursor.execute (SELECT * FROM VERYLARGETABLE)" никогда не завершается ... я выяснил границу в 2 миллиона записей в 4 столбцах, где сервер mysql завершил запрос после 30 секунд, но процесс python продолжает работать часами ... возможно, это ошибка в библиотеке Python MySQLDB ..

ТАК ВТОРАЯ ПОПЫТКА: функция db.query с db.use_results () и fetch_row ():

db = mysqldb.connect()
cursor = db.cursor()
db.query(SELECT * FROM VERYLARGETABLE)
large = large.use_result()
while true:
    for row in large.fetch_row(100000):
        file.write(row)
    if timetoUpdateStatus: cursor.execute(UPDATE STATUS) <-- ERROR (2014, "Commands out of sync; you can't run this command now")

так что THIRD TRY использовал 2 MySQL-соединения ... что не работает, когда я открываю второе соединение, первое исчезает ....

есть предложения ??

Ответы [ 3 ]

6 голосов
/ 17 мая 2011

Попробуйте использовать MySQL SSCursor .Он будет сохранять набор результатов на сервере (структура данных MySQL), а не передавать набор результатов клиенту (структура данных Python), как это делает курсор по умолчанию.Использование SSCursor позволит избежать длительной начальной задержки, вызванной курсором по умолчанию, который пытается построить структуру данных Python и выделить для нее огромный набор результатов.Таким образом, SSCursor также должен требовать меньше памяти.

import MySQLdb
import MySQLdb.cursors
import config

cons = [MySQLdb.connect(
    host=config.HOST, user=config.USER,
    passwd=config.PASS, db=config.MYDB,
    cursorclass=MySQLdb.cursors.SSCursor) for i in range(2)]
select_cur, update_cur = [con.cursor() for con in cons]
select_cur.execute(SELECT * FROM VERYLARGETABLE)
for i, row in enumerate(select_cur):
    print(row)
    if i % 100000 == 0 or timetoUpdateStatus:
        update_cur.execute(UPDATE STATUS)
3 голосов
/ 17 мая 2011

Попробуйте разбить запрос "select * from db" на более мелкие куски

index=0
while True:
    cursor.execute('select * from verylargetable LIMIT %s,%s', (index, index+10000))
    records = cursor.fetchall()
    if len(records)==0:
          break
    file.write(records)
    index+=10000
file.close()
2 голосов
/ 17 мая 2011

Используйте оператор LIMIT в вашем большом выборе:

limit = 0
step = 10000
query = "SELECT * FROM VERYLARGETABLE LIMIT %d, %d"
db = mysqldb.connect()
cursor = db.cursor()
while true:
    cursor.execute(query, (step, limit))
    for row in cursor.fetch_all():
        file.write(row)
    if timetoUpdateStatus:
        cursor.execute(update_query)
    limit += step

Код не проверен, но вы должны понять.

...