Я пытаюсь прочитать данные из db оракула. Я должен прочитать на python результаты простого выбора, который возвращает миллион строк.
Я использую функцию fetchall()
, изменяя свойство arraysize курсора.
select_qry = db_functions.read_sql_file('src/data/scripts/03_perimetro_select.sql')
dsn_tns = cx_Oracle.makedsn(ip, port, sid)
con = cx_Oracle.connect(user, pwd, dsn_tns)
start = time.time()
cur = con.cursor()
cur.arraysize = 1000
cur.execute('select * from bigtable where rownum < 10000')
res = cur.fetchall()
# print res # uncomment to display the query results
elapsed = (time.time() - start)
print(elapsed, " seconds")
cur.close()
con.close()
Если я удалю условие where rownum < 10000
среда python зависает, и функция fetchall()
никогда не заканчивается.
После некоторых испытаний я нашел предел для этого точного выбора, он работает до 50k строк, но он не работает, если я выберу 60k строк.
Что вызывает эту проблему? Должен ли я найти другой способ получить этот объем данных или проблема связана с ODBC-соединением? Как я могу проверить его?
На компьютере, на котором запущен cx_Oracle, наверняка не хватает памяти. Не используйте fetchall()
потому что для этого требуется cx_Oracle для хранения всего результата в памяти. Используйте что-то подобное, чтобы получить партии записей:
cursor = connection.cursor()
cursor.execute("select employee_id from employees")
res = cursor.fetchmany(numRows=3)
print(res)
res = cursor.fetchmany(numRows=3)
print(res)
Придерживайте fetchmany()
в цикле, обрабатывайте каждую партию строк в своем приложении перед извлечением следующего набора строк и выходите из цикла, когда данных больше нет.
Какое решение вы используете, настройте cursor.arraysize
чтобы получить лучшую производительность.
Также стоит рассмотреть уже заданное предложение повторить запрос и выбрать подмножества строк. Если вы используете Oracle DB 12, существует более новый (более простой) синтаксис, такой как SELECT * FROM mytab ORDER BY id OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY
.
PS cx_Oracle не использует ODBC.
Попробуйте запустить в пакетах с использованием Oracle ROWNUM
. Чтобы объединить обратно в один объект, добавьте в растущий список. Ниже предполагается, что общее количество строк для таблицы составляет 1 мил. Отрегулируйте по мере необходимости:
table_row_count = 1000000
batch_size = 10000
# PREPARED STATEMENT
sql = """SELECT t.* FROM
(SELECT *, ROWNUM AS row_num
FROM
(SELECT * FROM bigtable ORDER BY primary_id) sub_t
) AS t
WHERE t.row_num BETWEEN :LOWER_BOUND AND :UPPER_BOUND;"""
data = []
for lower_bound in range(0, table_row_count, batch_size):
# BIND PARAMS WITH BOUND LIMITS
cursor.execute(sql, {'LOWER_BOUND': lower_bound,
'UPPER_BOUND': lower_bound + batch_size - 1})
for row in cur.fetchall():
data.append(row)
arraysize
?