Я вставляю миллионы строк в MySQL с помощью Python3, но я обнаружил, что использование памяти продолжает расти и, наконец, достигло 64 ГБ. Я попытался диагностировать проблему, и вот воспроизведение проблемы: скажем, у меня есть 100 файлов CSV. Каждый файл содержит 50000 строк, и я хочу вставить их в базу данных. Вот пример кода:
import mysql.connector
insert_sql = ("INSERT INTO table (Value) VALUES (%s)")
for i in range(100):
cnx = mysql.connector.connect(user='root', password='password', host='127.0.0.1', database='database')
cursor = cnx.cursor()
# Insert 50000 rows here
for j in range(50000):
cursor.execute(insert_sql, (j,))
cnx.commit()
cursor.close()
cnx.close()
print('Finished processing one file')
print('All done')
В базе данных всего 1 таблица с 2 столбцами:
CREATE TABLE `table` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Value` int(11) NOT NULL,
PRIMARY KEY (`Id`)
)
Окружающая среда: Mac OS Sierra; Python 3.6.x; MySQL 8.0.1; MySQL-коннектор-Python 8.0.11
Я понимаю, что перед фиксацией объем памяти должен увеличиться, потому что изменения буферизуются. Но я предполагал, что после фиксации она уменьшится. Однако это не. Поскольку в моем реальном приложении у меня есть тысячи файлов по 100 МБ каждый, моя память взорвется.
Я здесь что-то не так сделал? (Я новичок в базе данных) Как я могу контролировать использование памяти? Любое предложение будет оценено по достоинству!
Обновлено: я также пробовал следующий код в соответствии с комментариями и ответами, но он все еще не работает:
import mysql.connector
insert_sql = ("INSERT INTO table (Value) VALUES (%s)")
for i in range(100):
cnx = mysql.connector.connect(user='root', password='password', host='127.0.0.1', database='database')
cursor = cnx.cursor()
params = [(j,) for j in range(50000)]
# If I don't excute the following insertion, the memory is stable.
cnx.executemany(insert_sql, params)
cnx.commit()
cursor.close()
del cursor
cnx.close()
del cnx
print('Finished processing one file')
print('All done')
Также попробуйте использовать ? вместо %s
@AndrejKesely Да, я пытался объединить все параметры в один список и использовать executemany() для их вставки, но объем памяти все равно растет.
@RedEyed Спасибо, но я попробовал ?, тоже не работает.






Попробуйте выполнить пакетное выполнение, проблема может быть в этом цикле вставок.
Вы можете сделать исполнение:
c.executemany("INSERT INTO table (Value) VALUES (%s)",
[('a'),('b')])
или большой оператор вставки со всеми значениями, которые вы хотите одновременно.
Спасибо за быстрый ответ. Я попытался собрать все значения в один список и один раз использовать executemany() для файла, но это тоже не работает. После закрытия соединения рост памяти не прекращается.
Это проблема с объектом sql или со списком, который вы передали? Попробуйте сделать `del cnx
@RedEyed Я думаю, что проблема в sql, потому что если я создаю список только из 50000 элементов, но не использую executemany(), использование памяти будет стабильным. Я также пробовал del cursor и del cnx после close(), но они все еще не работают.
Вроде есть ошибка
@RedEyed Спасибо за ваш ответ. Я не думаю, что это связано с указанной проблемой, потому что я вставил целое число, а не строку Unicode. Но я только что сообщил об этой проблеме в MySQL, если это действительно ошибка.
Вы пробовали
executemany()вместо многихexecute()в цикле?