【问题标题】:Improve performance SQL query in Python Cx_Oracle提高 Python Cx_Oracle 中的性能 SQL 查询
【发布时间】:2018-09-19 09:51:11
【问题描述】:

我实际上使用 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 表有超过 100 000 行,它会非常慢,因为我在 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()

【问题讨论】:

  • id1id2ora_table 中是否定义为not null
  • 是的,表中没有缺失值。我改用“NF”。
  • 但是实际的列定义是否包括NOT NULL?这与是否填充所有值不同。
  • 我不清楚对不起。是的,在Oracle目标表定义中,ID1和ID2不是NULLABLE
  • 什么是 Python 数据集?你是说熊猫数据框吗?

标签: python sql oracle cx-oracle


【解决方案1】:

这是一个可能的解决方案,可能会有所帮助:您拥有的 sql 具有 OR 条件,并且对于给定值,该条件中只有一部分为真。因此,我将通过检查以下代码并构造两个插入而不是一个插入将其分为两部分,并且在任何时间点,只有一个会执行: 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 的值是多少,并根据该值使用两个简化的插入。请检查这在功能上是否与原始查询相同,并验证它是否提高了响应时间。

【讨论】:

    【解决方案2】:

    假设是 Pandas,请考虑将您的数据导出为一个表,以用作最终迁移的暂存,其中您只运行一次子查询一次,而不是为每一行数据集。在 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 1970-01-01
      • 2016-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多