Как создать большой фреймворк pandas из SQL-запроса без исчерпания памяти?
У меня проблемы с запросом таблицы> 5 миллионов записей из базы данных MS SQL Server. Я хочу выбрать все записи, но мой код, похоже, дает сбой при выборе большого количества данных в памяти.
Это работает:
import pandas.io.sql as psql
sql = "SELECT TOP 1000000 * FROM MyTable"
data = psql.read_frame(sql, cnxn)
... но это не работает:
sql = "SELECT TOP 2000000 * FROM MyTable"
data = psql.read_frame(sql, cnxn)
Возвращает эту ошибку:
File "inference.pyx", line 931, in pandas.lib.to_object_array_tuples
(pandas\lib.c:42733) Memory Error
Я прочитал здесь, что похожая проблема существует при создании dataframe
из файла CSV, и что обходной путь должен использовать параметры 'iterator' и 'chunksize', подобные этим:
read_csv('exp4326.csv', iterator=True, chunksize=1000)
Есть ли подобное решение для запросов из базы данных SQL? Если нет, какой предпочтительный обходной путь? Должен ли я использовать некоторые другие методы для чтения записей в кусках? Я прочитал немного обсуждения здесь о работе с большими наборами данных в пандах, но кажется, что для выполнения запроса SELECT * требуется много работы. Конечно, есть более простой подход.
Ответы
Ответ 1
Обновление. Обязательно ознакомьтесь с нижеприведенным ответом, так как Pandas теперь имеет встроенную поддержку для загрузки пакетов.
Вы могли бы просто попытаться прочитать входную таблицу chunk-wise и собрать ваш полный кадр данных из отдельных частей после этого, например:
import pandas as pd
import pandas.io.sql as psql
chunk_size = 10000
offset = 0
dfs = []
while True:
sql = "SELECT * FROM MyTable limit %d offset %d order by ID" % (chunk_size,offset)
dfs.append(psql.read_frame(sql, cnxn))
offset += chunk_size
if len(dfs[-1]) < chunk_size:
break
full_df = pd.concat(dfs)
Возможно также, что весь фреймворк данных просто слишком велик, чтобы вписаться в память, в этом случае у вас не будет другого выбора, кроме как ограничить количество выбранных строк или столбцов.
Ответ 2
Как указано в комментарии, начиная с pandas 0.15, у вас есть опция chunksize в read_sql
, чтобы читать и обрабатывать кусок запроса куском:
sql = "SELECT * FROM My_Table"
for chunk in pd.read_sql_query(sql , engine, chunksize=5):
print(chunk)
Ссылка: http://pandas.pydata.org/pandas-docs/version/0.15.2/io.html#querying
Ответ 3
Базовое решение моего вопроса: получите больше памяти:
Моя компания имеет высокопроизводительный компьютер с 64 ГБ оперативной памяти (16 раз на моей машине). Я попытался подключиться к этой машине и запустить свой код. К моему удовольствию, он работал без ошибок памяти!
Это не будет жизнеспособным решением для всех с этой проблемой памяти, но если у вас есть этот вариант, он может выполнить свою работу.
HDF5 выглядит как лучший способ найти более постоянное решение, описанное @Jeff.
Ответ 4
Кодовое решение и замечания.
# Create empty list
dfl = []
# Create empty dataframe
dfs = pd.DataFrame()
# Start Chunking
for chunk in pd.read_sql(query, con=conct, ,chunksize=10000000):
# Start Appending Data Chunks from SQL Result set into List
dfl.append(chunk)
# Start appending data from list to dataframe
dfs = pd.concat(dfl, ignore_index=True)
Тем не менее, мой анализ памяти говорит мне, что, хотя память освобождается после извлечения каждого чанка, список увеличивается и увеличивается и занимает эту память, в результате чего чистая оперативная память не увеличивается.
Хотелось бы услышать, что автор/другие говорят.