提高Python Cx_Oracle中的SQL查询性能

时间:2018-09-19 09:51:11

标签: python sql oracle cx-oracle

我实际上使用Python中的Cx_Oracle库与我的数据库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()

在某些情况下,我的查询之一将python数据帧的INSERT写入我的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表具有超过10万行,那将非常慢,因为我在WHERE条件下通读了所有表。

是否有一种方法可以通过join或其他方式提高此查询的性能?

代码结尾:

# 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 :(得分:0)

这是一个可能有用的解决方案,它可能会有所帮助:您拥有的sql具有OR条件,并且对于给定值,该条件中只有一部分为真。因此,我将通过检查代码中的以下 将其分为两部分,并构造两个插入而不是一个插入,并且在任何时间点仅执行一次: IF:1!='NF'然后使用以下插入内容:

 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的值是什么,并根据情况使用两个简化的插入。请检查此功能是否与原始查询相同,并验证它是否可以缩短响应时间。

答案 1 :(得分:0)

假设是熊猫,请考虑将数据导出为表以用作最终迁移的阶段,在此迁移中,您仅一次而不是对每一行数据集都运行子查询。在Pandas中,您需要与sqlalchemy进行交互才能运行to_sql导出操作。注意:这是假设您的连接用户具有DROP TABLECREATE 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)