Произвольный выбор при неудачном использовании cx_Oracle с мгновенным клиентом

Я пытаюсь выбрать данные из базы данных 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 байтов.


person avatarofhope2    schedule 15.04.2019    source источник
comment
Можете ли вы предоставить полный пример, который можно запустить - с SQL для создания таблиц, SQL для заполнения таблиц и кодом Python - который демонстрирует проблему? Я делал такие вещи без каких-либо трудностей. Кроме того, укажите полностью номера версий клиента и базы данных.   -  person Anthony Tuininga    schedule 16.04.2019


Ответы (1)


Думаю, я наконец нашел способ заставить все работать. Наконец я наткнулся на эту ссылку:

https://ardentperf.com/2010/09/08/mysterious-oracle-net-errors/

Оказывается, это решило мою проблему. У меня все еще возникают проблемы с тем, чтобы cx_Oracle соблюдал строку подключения того же формата, что и файл tnsnames.ora, но я изменил свой код, чтобы он теперь ссылался на tnsnames.ora следующим образом:

connection_info = {
    'user': self.config.get(self.db, 'user'),
    'pass': self.config.get(self.db, 'password')
}
connection_string = '{user}/{pass}@TEST'\
    .format(**connection_info)
connection = cx_Oracle.connect(connection_string)

где мой tnsnames.ora содержит следующее:

TEST =
 (DESCRIPTION =
   (ADDRESS_LIST =
     (ADDRESS = (PROTOCOL = TCP)(Host = myhost.com)(Port = 1521))
   )
   (SDU=1024)
 (CONNECT_DATA =
   (SID=mysid)
 )
)

Ключевым моментом здесь является SDU = 1024, который необъяснимым образом решает эту проблему.

https://docs.oracle.com/cd/B28359_01/network.111/b28317/sqlnet.htm#NETRF184

Документация из приведенной выше ссылки указывает, что значение по умолчанию для SDU составляет 8192 байта (8 КБ), и я понимаю, что предполагается автоматическое согласование этого значения. Похоже, что это не так, и я не знаю, какие были значения по умолчанию в прошлом.

person avatarofhope2    schedule 17.04.2019