Повышение производительности SQL-запросов в Python Cx_Oracle - PullRequest
0 голосов
/ 19 сентября 2018

Я на самом деле использую библиотеку Cx_Oracle в Python для работы с моей базой данных Oracle.

import cx_Oracle as Cx

# Parameters for server connexion
dsn_tns = Cx.makedsn(_ip, _port, service_name=_service_name)

# Connexion with Oracle Database
db = Cx.connect(_user, _password, dsn_tns)

# Obtain a cursor for make SQL query
cursor = db.cursor()

Один из моих запросов записывает в INSERT кадра данных Python в моей целевой таблице Oracle среди некоторых условий.

query = INSERT INTO ORA_TABLE(ID1, ID2) 
SELECT :1, :2
FROM DUAL 
WHERE (:1 != 'NF' AND :1 NOT IN (SELECT ID1 FROM ORA_TABLE)) 
   OR (:1 = 'NF' AND :2 NOT IN (SELECT ID2 FROM ORA_TABLE))

Цель этого запроса - записать в WHERE только те строки, которые соответствуют условиям.

На самом деле этот запрос работает хорошо, когда в моей целевой таблице Oracle есть несколько строк.Но если в моей целевой таблице Oracle содержится более 100 000 строк, это очень медленно, потому что я читаю всю таблицу в состоянии WHERE.

Есть ли способ улучшить производительность этого запроса с помощью соединения или чего-то еще?

Конец кода:

# SQL query incoming
cursor.prepare(query)

# Launch query with Python dataset
cursor.executemany(None, _py_table.values.tolist())

# Commit changes into Oracle database
db.commit()

# Close the cursor
cursor.close()

# Close the server connexion
db.close()

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Предполагая, что Pandas, рассмотрите возможность экспорта данных в виде таблицы, которая будет использоваться в качестве промежуточной для окончательной миграции, когда вы выполняете свой подзапрос только один раз , а не для каждой строки набора данных.В Pandas вам нужно будет взаимодействовать с sqlalchemy , чтобы запустить операцию экспорта to_sql.Примечание. Предполагается, что у подключенного пользователя есть такие привилегии DROP TABLE и CREATE TABLE.

Также рассмотрите возможность использования подзапроса EXISTS для объединения обоих подзапросов IN.Ниже подзапрос пытается выполнить противоположность вашей логике для исключения.

import sqlalchemy

...
engine = sqlalchemy.create_engine("oracle+cx_oracle://user:password@dsn")

# EXPORT DATA -ALWAYS REPLACING
pandas_df.to_sql('myTempTable', con=engine, if_exists='replace')

# RUN TRANSACTION
with engine.begin() as cn:
   sql = """INSERT INTO ORA_TABLE (ID1, ID2)
            SELECT t.ID1, t.ID2
            FROM myTempTable t
            WHERE EXISTS 
                (
                  SELECT 1 FROM ORA_TABLE sub
                  WHERE (t.ID1 != 'NF' AND t.ID1 = sub.ID1)
                     OR (t.ID1  = 'NF' AND t.ID2 = sub.ID2) 
                )
         """
   cn.execute(sql)
0 голосов
/ 19 сентября 2018

Вот возможное решение, которое может помочь: SQL, который у вас есть, имеет условие ИЛИ, и только одна часть этого условия будет истинной для данного значения.Поэтому я бы разделил его на две части, проверив следующее в коде и построив две вставки вместо одной, и в любой момент времени будет выполняться только одна: IF: 1! = 'NF'then используйте следующую вставку:

 INSERT INTO ORA_TABLE (ID1, ID2)
   SELECT :1, :2
     FROM DUAL
    WHERE (:1 NOT IN (SELECT ID1
                        FROM ORA_TABLE));

и IF: 1 =' NF ', тогда используйте следующую вставку:

INSERT INTO ORA_TABLE (ID1, ID2)
   SELECT :1, :2
     FROM DUAL
    WHERE (:2 NOT IN (SELECT ID2
                        FROM ORA_TABLE));

Так что выпроверьте в коде, каково значение: 1 и в зависимости от этого используйте две упрощенные вставки.Пожалуйста, проверьте, совпадает ли это функционально с оригинальным запросом, и проверьте, улучшает ли это время ответа.

...