我实际上使用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()
答案 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 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)