Я пытаюсь выбрать данные из базы данных ORACLE 12c с помощью cx_Oracle, но получаю исключение: «cx_Oracle.OperationalError: ORA-03113: конец файла на канале связи».
Мой запрос отлично работает с Pycharm (jdbc: oracle: thin driver). Однако при использовании cx_Oracle в python 3.6 запрос завершится ошибкой, если я не уменьшу количество идентификаторов в предложении IN с 500 до примерно 250. Функция Cursor.fetchall () - это то, что вызывает исключение. У меня нет привилегированного доступа к базе данных для проверки таких вещей, как блокировки или загрузка, но может ли это быть причиной проблемы? По словам нашего администратора базы данных, на сервере Oracle db все в порядке, и, поскольку в остальном запрос работает нормально, я склонен в это верить. Я также испортил клиентский sqlnet.ora, который позволил в конечном итоге выбрасывать исключения вместо того, чтобы зависать вечно, но я все еще не могу получить данные.
def select(self, query, *args):
cur = self.dbh.cursor()
cur.prepare(query)
try:
cur.execute(None, args)
return cur.fetchall()
# my attempt to handle the issue
except (cx_Oracle.OperationalError, cx_Oracle.DatabaseError) as e:
# cx_Oracle.OperationalError: ORA-03113: end-of-file on communication channel
self.logger.error('Oracle Error: {}'.format(traceback.format_exc()))
raise e
Код вызывает select как это. Для краткости я опустил полные идентификаторы строк.
ids = ['1', '2', '3', ...]
query = """\
select * from my_table where id in(:0,:1,:2,:3,:4, ...)
"""
self.select(query, *ids)
Запрос не выполняется без заполнителей (с идентификаторами, помещенными непосредственно в запрос).
Я ожидаю, что смогу выполнить любой запрос выбора с использованием предложения IN с идентификаторами до 1000 без получения исключения ORA-03113.
Изменить: я установил oracle-instantclient18.5-basic-18.5.0.0.0-3.x86_64.rpm * на ubuntu 18.04.2, у меня cx_Oracle версии 7.1.2, и я подключаюсь к Oracle 12.1.0.2.0.
Запрос находится в базовых таблицах ARS BMC Software. Я начну работать, чтобы попытаться воспроизвести проблему с локальной структурой таблицы, но это беспорядок и займет некоторое время. Если я смогу создать локальную копию таблиц, я не уверен, что смогу воспроизвести проблему, поскольку идентичные запросы с разными идентификаторами работают нормально. Это заставляет меня казаться управляемым данными, однако после того, как я сократил запрос до 250 идентификаторов, я поменял 250 из первой половины на вторую половину и получил тот же результат успеха, поэтому это не похоже на одну плохую строку .
Есть ли более полезные журналы, которые я могу включить на стороне клиента, чтобы получить больше информации?
Edit2: Я также должен добавить, что проблема возникает не только с одним запросом. Я видел ту же проблему с выбранными запросами к совершенно другим таблицам.
Edit3: Я только что узнал, что, закомментировав некоторые из столбцов, которые я выбираю, также можно заставить запрос работать. столбцы вроде этого:
to_char(to_date('1970-01-01','YYYY-MM-DD') + numtodsinterval(EventStart,'SECOND'),'YYYY-MM-DD HH24:MI:SS')
Это может означать, что достигнут какой-то тайм-аут, который может быть настроен или не настроен в моем sqlnet.ora:
DISABLE_OOB=on
SQLNET.RECV_TIMEOUT=60
SQLNET.SEND_TIMEOUT=60
TCP.CONNECT_TIMEOUT=300
SQLNET.OUTBOUND_CONNECT_TIMEOUT=300
ENABLE=BROKEN
TRACE_LEVEL_CLIENT=ADMIN
TRACE_FILE_CLIENT=sqlnet
Изменить 4: я пробовал еще кое-что.
Я установил ту же версию мгновенного клиента, за исключением компьютера с Windows 7, и выполнил тот же запрос к тому же экземпляру db. Запрос выполнен.
Я также сузил, что для этого конкретного запроса он будет принимать 499 идентификаторов, но не работает с 500. Неважно, какой идентификатор я закомментирую из запроса.
Я также попытался обмануть запрос, заставив думать, что было меньше идентификаторов, используя вместо этого подвыбор:
IN(
select regexp_substr(:0,'[^,]+', 1, level) from dual connect by regexp_substr(:0, '[^,]+', 1, level) is not null
)
Я получил сообщение об ошибке «cx_Oracle.DatabaseError: ORA-01460: запрошено нереализованное или необоснованное преобразование», после чего я понял, что имеет смысл, потому что Oracle разрешает длину строки только до 4000 байтов.