Подтвердить что ты не робот

Чтение большой таблицы с миллионами строк из Oracle и запись на HDF5

Я работаю с базой данных Oracle с миллионами строк и более 100 столбцов. Я пытаюсь сохранить эти данные в файле HDF5, используя pytables с индексированными столбцами. Я буду читать подмножества этих данных в pandas DataFrame и выполнять вычисления.

Я попытался сделать следующее:

Загрузите таблицу, используя утилиту в файл csv, прочитайте кусок файла csv с помощью chunk с помощью pandas и добавьте в таблицу HDF5 с помощью pandas.HDFStore. Я создал определение dtype и предоставил максимальные размеры строк.

Однако теперь, когда я пытаюсь загрузить данные непосредственно из Oracle DB и отправить его в файл HDF5 через pandas.HDFStore, я столкнулся с некоторыми проблемами.

pandas.io.sql.read_frame не поддерживает чтение каналов. У меня недостаточно памяти, чтобы сначала загрузить все данные в память.

Если я пытаюсь использовать cursor.fecthmany() с фиксированным количеством записей, операция чтения занимает много времени в таблице БД, не индексируется, и мне приходится читать записи, подпадающие под диапазон дат. Я использую DataFrame(cursor.fetchmany(), columns = ['a','b','c'], dtype=my_dtype) однако созданный DataFrame всегда указывает тип dtype, а не навязывает dtype, который я предоставил (в отличие от read_csv, который придерживается dtype, который я предоставляю). Следовательно, когда я добавляю этот DataFrame к уже существующему HDFDatastore, существует несоответствие типа, например. float64 может интерпретироваться как int64 в одном фрагменте.

Цените, если вы, ребята, можете предложить свои мысли и указать мне в правильном направлении.

4b9b3361

Ответ 1

Ну, единственное практическое решение на данный момент - использовать PyTables напрямую, поскольку оно предназначено для работы вне памяти... Это немного утомительно, но не так уж плохо:

http://www.pytables.org/moin/HintsForSQLUsers#Insertingdata

Другой подход, используя Pandas, находится здесь:

"Большие данные" рабочие потоки с использованием pandas

Ответ 2

Хорошо, поэтому у меня нет большого опыта работы с базами данных оракула, но здесь некоторые мысли:

Ваше время доступа для любых записей из oracle медленное, из-за отсутствия индексации и того факта, что вы хотите данные в timestamp-порядке.

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

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

Вы можете хранить эти данные как единый массив уникальных идентификаторов, и вы должны быть в состоянии вписаться в память. Если вы разрешаете 4k для каждого уникального ключа (консервативная оценка, включает в себя накладные расходы и т.д.), И вы не сохраняете временные метки, поэтому это всего лишь массив целых чисел, он может использовать около 1,1 ГБ оперативной памяти для 3 миллионов записей. Это не целая куча, и, по-видимому, вам нужно только небольшое окно активных данных, или, может быть, вы обрабатываете строку за строкой?

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

Если вы не можете сохранить все это в памяти или по какой-то другой причине это не сработает, то самое лучшее, что вы можете сделать, - это выяснить, сколько вы можете хранить в памяти. Вы можете разделить задание на несколько запросов и использовать многопоточность для отправки запроса после завершения последнего, в то время как вы обрабатываете данные в новом файле. Он не должен использовать память, пока вы не попросите вернуть данные. Попробуйте и выясните, является ли задержка выполняемым запросом или загружаемыми данными.

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