cx_oracle: fetchall перестает работать с большими инструкциями select - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь прочитать данные из оракула БД.Мне нужно прочитать на python результаты простого выбора, который возвращает миллион строк.

Я использую функцию fetchall(), изменяя свойство массива курсора.

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 where rownum < 10000, среда python зависает и функция fetchall() никогда не заканчивается.

После некоторых испытаний я нашел предел для этого точного выбора, он работает до 50 тыс. Строк, но не работает, еслиЯ выбираю 60 тыс. Строк.

В чем причина этой проблемы?Должен ли я найти другой способ получить этот объем данных или проблема в соединении ODBC?Как я могу проверить это?

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Возможно, вам не хватает памяти на компьютере, на котором запущен 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.

0 голосов
/ 06 декабря 2018

Рассмотрите возможность запуска в пакетах с использованием 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)
...