Произвольный выбор неудачен с помощью cx_Oracle с мгновенным клиентом - PullRequest
0 голосов
/ 16 апреля 2019

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

Код звонков выбирается так. Для краткости я опустил полные строковые идентификаторы

ids = ['1', '2', '3', ...]
query = """\
select * from my_table where id in(:0,:1,:2,:3,:4, ...)
"""
self.select(query, *ids)

Сбой запроса также без заполнителей (с идентификаторами, размещенными непосредственно в запросе).

Я ожидаю, что смогу выполнить любой запрос select с помощью предложения IN с 1000 идентификаторами без получения исключения ORA-03113.

Edit: Я установил на Ubuntu 18.04.2 oracle-instantclient18.5-basic-18.5.0.0.0-3.x86_64.rpm *, у меня 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: я пробовал еще кое-что.

Я установил ту же версию клиента Instant Instant, за исключением Windows 7, и выполнил тот же запрос к тому же экземпляру БД. Запрос успешно выполнен.

Я также сузил, что для этого конкретного запроса он будет принимать 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 байт.

1 Ответ

0 голосов
/ 17 апреля 2019

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

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 КБ), и я понимаю, что предполагается автоматическое согласование этого значения. Похоже, это не так, и я не знаю, какие были значения по умолчанию в прошлом.

...