cx_oracle: fetchall перестает работать с большими инструкциями select

1

Я пытаюсь прочитать данные из 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-соединением? Как я могу проверить его?

  • 0
    Вы можете использовать инструмент (ы) разработки SQL для выполнения запроса и посмотреть, есть ли проблемы?
  • 0
    Кроме того, в чем смысл изменения arraysize ?
Показать ещё 1 комментарий
Теги:
odbc
cx-oracle

2 ответа

2

На компьютере, на котором запущен 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
    Я создаю цикл с вашим предложением, но он останавливается после 12500 извлеченных строк, независимо от размера массива. Может ли быть какое-то ограничение на соединение или на пользователя БД?
  • 0
    Освобождаете ли вы память в конце каждой итерации цикла перед следующей итерацией?
Показать ещё 2 комментария
1

Попробуйте запустить в пакетах с использованием 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)
  • 1
    без ORDER BY unique_key_col и вложенного представления ROWNUM не может быть непротиворечивым и ROWNUM . Должно быть что-то вроде этого, чтобы оно работало, или лучше как это (Oracle12c и выше)
  • 0
    Интересно ... спасибо @KaushikNayak. Я не эксперт по Oracle.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню