Вложенные запросы с использованием MySQLdb

Я пытаюсь добиться следующего, используя Python и интерфейс MySQLdb:

  1. Прочитайте содержимое таблицы, содержащей несколько миллионов строк.
  2. Обработайте и измените вывод каждой строки.
  3. Поместите измененные строки в другую таблицу.

Мне кажется разумным перебирать каждую строку, обрабатывать «на лету», а затем вставлять каждую новую строку в новую таблицу «на лету».

Это работает:

import MySQLdb
import MySQLdb.cursors

conn=MySQLdb.connect(
    host="somehost",user="someuser",
    passwd="somepassword",db="somedb")

cursor1 = conn.cursor(MySQLdb.cursors.Cursor)
query1 = "SELECT * FROM table1"
cursor1.execute(query1)

cursor2 = conn.cursor(MySQLdb.cursors.Cursor)

for row in cursor1:
    values = some_function(row)
    query2 = "INSERT INTO table2 VALUES (%s, %s, %s)"
    cursor2.execute(query2, values)

cursor2.close()
cursor1.close()
conn.commit()
conn.close()

Но это медленно и отнимает много памяти, поскольку для запроса SELECT используется курсор на стороне клиента. Если вместо этого я использую курсор на стороне сервера для запроса SELECT:

cursor1 = conn.cursor(MySQLdb.cursors.SSCursor)

Затем я получаю ошибку 2014 года:

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

Так что, похоже, ему не нравится запускать другой курсор во время итерации над курсором на стороне сервера. Что, кажется, оставляет меня застрявшим с очень медленным итератором на стороне клиента.

Какие-либо предложения?


person edanfalls    schedule 28.01.2011    source источник
comment
Хотя это и не связано с вашей технической проблемой (которая заключается в том, что вам нужно прочитать весь буфер набора результатов перед запуском другого запроса), вы уверены, что не можете переписать этот код как один запрос INSERT INTO ... SELECT, где SELECT выполняет логику вашего some_function было выполнять? MySQL может многое сделать прямо внутри запроса.   -  person Dan Grossman    schedule 28.01.2011
comment
С таблицей, с которой я сейчас работаю, я, вероятно, мог бы, да. Более серьезная проблема (которую я должен был указать в вопросе - всегда что-то упускаю!) заключается в том, что в будущем у меня будет гораздо больше этих таблиц для чтения, и я не знаю, какие функции мне нужно для выполнять на тех еще. Я полагаю, что обработка в Python, а не в MySQL, защитит меня от всего, что может случиться в будущем. Спасибо за комментарий - возможно, мне придется прибегнуть к обработке MySQL, если это необходимо.   -  person edanfalls    schedule 28.01.2011


Ответы (1)


Вам нужно отдельное подключение к базе данных, так как первое подключение застряло с потоковой передачей набора результатов, вы не можете запустить запрос на вставку.

Попробуй это:

import MySQLdb
import MySQLdb.cursors

conn=MySQLdb.connect(
    host="somehost",user="someuser",
    passwd="somepassword",db="somedb")

cursor1 = conn.cursor(MySQLdb.cursors.SSCursor)
query1 = "SELECT * FROM table1"
cursor1.execute(query1)

insertConn=MySQLdb.connect(
    host="somehost",user="someuser",
    passwd="somepassword",db="somedb")
cursor2 = inserConn.cursor(MySQLdb.cursors.Cursor)

for row in cursor1:
    values = some_function(row)
    query2 = "INSERT INTO table2 VALUES (%s, %s, %s)"
    cursor2.execute(query2, values)

cursor2.close()
cursor1.close()
conn.commit()
conn.close()
insertConn.commit()
insertConn.close()
person Iberê    schedule 08.09.2015