Python 有没有改进合并查询的方法?

Python 有没有改进合并查询的方法?,python,oracle,Python,Oracle,我使用此查询将新条目插入到我的表中 使用DUAL-ON(CLEAN.id=:id)合并到CLEAN-CLEAN中 如果不匹配,则插入(ID,COUNT)值(:ID,:xcount) 匹配后,更新集clean.COUNT=clean.COUNT+:xcount 似乎我做的inserts比updates更多,有没有办法提高我当前的绩效 我正在将cx_Oracle与Python 3和OracleDB 19c一起使用。MERGE相当快。插入比更新更快,我会说(通常) 所以,如果你问如何使插入更快,那就

我使用此查询将新条目插入到我的表中

使用DUAL-ON(CLEAN.id=:id)合并到CLEAN-CLEAN中
如果不匹配,则插入(ID,COUNT)值(:ID,:xcount)
匹配后,更新集clean.COUNT=clean.COUNT+:xcount
似乎我做的
insert
s比
update
s更多,有没有办法提高我当前的绩效


我正在将cx_Oracle与Python 3和OracleDB 19c一起使用。

MERGE
相当快。插入比更新更快,我会说(通常)

所以,如果你问如何使插入更快,那就要看情况了

  • 如果一次插入一行,则不应出现任何瓶颈
  • 如果要插入数百万行,请查看表上是否启用了触发器,这些触发器为每行触发并执行某些操作(减慢进程)
截至更新时,
clean.id
列上是否有索引?如果没有,可能会有所帮助


否则,看看解释计划是怎么说的;定期收集统计数据。

MERGE
相当快。插入比更新更快,我会说(通常)

所以,如果你问如何使插入更快,那就要看情况了

  • 如果一次插入一行,则不应出现任何瓶颈
  • 如果要插入数百万行,请查看表上是否启用了触发器,这些触发器为每行触发并执行某些操作(减慢进程)
截至更新时,
clean.id
列上是否有索引?如果没有,可能会有所帮助

否则,看看解释计划是怎么说的;定期收集统计数据。

如果您的方法存在大量问题,则很可能在列
clean.id
上缺少索引,这是当
合并
使用
作为每行的源时,您的方法所需的索引

当您说
id
是主键时,这种可能性较小

因此,基本上你做的是正确的思考,你会看到类似的情况,如下所示:

---------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                 |                 |       |       |     2 (100)|          |
|   1 |  MERGE                          | CLEAN           |       |       |            |          |
|   2 |   VIEW                          |                 |       |       |            |          |
|   3 |    NESTED LOOPS OUTER           |                 |     1 |    40 |     2   (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL           | DUAL            |     1 |     2 |     2   (0)| 00:00:01 |
|   5 |     VIEW                        | VW_LAT_A18161FF |     1 |    38 |     0   (0)|          |
|   6 |      TABLE ACCESS BY INDEX ROWID| CLEAN           |     1 |    38 |     0   (0)|          |
|*  7 |       INDEX UNIQUE SCAN         | CLEAN_UX1       |     1 |       |     0   (0)|          |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   7 - access("CLEAN"."ID"=:ID)
因此,执行计划是好的,有效的,但它有一个问题

请记住始终使用索引,处理几行时您会很高兴,但它不会缩放

如果您正在处理数百万条记录,您可能会退回到两步处理

  • 在临时表中插入所有行

  • 使用临时表执行单个
    MERGE
    语句

最大的优势是Oracle可以打开一个
散列连接
,并消除百万行中每一行的索引访问

以下是使用1M
id
(未显示)启动的
clean
表格测试示例,并执行1M插入和1M更新:

n  = 1000000
data2 = [{"id" : i, "xcount" :1} for i in range(2*n)]  

sql3 = """
    insert into tmp (id,count)
    values (:id,:xcount)"""
sql4 = """MERGE into clean USING tmp on (clean.id = tmp.id)
          when not matched then insert (id, count)  values (tmp.id, tmp.count)
          when matched then update set clean.count= clean.count + tmp.count"""    

cursor.executemany(sql3, data2)
cursor.execute(sql4)
该测试在一台计算机上运行。10秒,这不到您使用
MERGE
dual
接近的一半

如果这还不够,您将不得不使用并行选项。

如果您的方法存在大量问题,则很可能在列
clean.id
上缺少索引,当
合并
使用
作为每行的源时,您的方法需要该索引

当您说
id
是主键时,这种可能性较小

因此,基本上你做的是正确的思考,你会看到类似的情况,如下所示:

---------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                 |                 |       |       |     2 (100)|          |
|   1 |  MERGE                          | CLEAN           |       |       |            |          |
|   2 |   VIEW                          |                 |       |       |            |          |
|   3 |    NESTED LOOPS OUTER           |                 |     1 |    40 |     2   (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL           | DUAL            |     1 |     2 |     2   (0)| 00:00:01 |
|   5 |     VIEW                        | VW_LAT_A18161FF |     1 |    38 |     0   (0)|          |
|   6 |      TABLE ACCESS BY INDEX ROWID| CLEAN           |     1 |    38 |     0   (0)|          |
|*  7 |       INDEX UNIQUE SCAN         | CLEAN_UX1       |     1 |       |     0   (0)|          |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   7 - access("CLEAN"."ID"=:ID)
因此,执行计划是好的,有效的,但它有一个问题

请记住始终使用索引,处理几行时您会很高兴,但它不会缩放

如果您正在处理数百万条记录,您可能会退回到两步处理

  • 在临时表中插入所有行

  • 使用临时表执行单个
    MERGE
    语句

最大的优势是Oracle可以打开一个
散列连接
,并消除百万行中每一行的索引访问

以下是使用1M
id
(未显示)启动的
clean
表格测试示例,并执行1M插入和1M更新:

n  = 1000000
data2 = [{"id" : i, "xcount" :1} for i in range(2*n)]  

sql3 = """
    insert into tmp (id,count)
    values (:id,:xcount)"""
sql4 = """MERGE into clean USING tmp on (clean.id = tmp.id)
          when not matched then insert (id, count)  values (tmp.id, tmp.count)
          when matched then update set clean.count= clean.count + tmp.count"""    

cursor.executemany(sql3, data2)
cursor.execute(sql4)
该测试在一台计算机上运行。10秒,这不到您使用
MERGE
dual
接近的一半


如果这还不够,您将不得不使用parallel选项。

您的问题不是由
MERGE
语句引起的,而是由于您正在循环中调用它,即所谓的逐行调用,也称为slow by slow。您必须将其更改为一个
MERGE
语句的调用,在该语句中,您将
dual
替换为包含所有要处理的行的临时表。@MarmiteBomber,您能解释一下吗?我不太明白有一个很大的区别是我们调用一个
MERGE
来处理1M行(=快速),或者调用一个
MERGE
语句一百万次来处理一行(=慢得多,这是你的情况)。@MarmiteBomber有什么方法可以从python中实现吗?我只是使用execute\u many,因为肯定会有一种方法,发布整个语句,这样逻辑就可见了……您的问题不是由
MERGE
语句引起的,而是由于您在循环中调用它——所谓的逐行,也称为slow by slow。您必须将其更改为一个
MERGE
语句的调用,在该语句中,您将
dual
替换为包含所有要处理的行的临时表。@MarmiteBomber,您能解释一下吗?我不太明白有一个很大的区别是我们调用一个
MERGE
来处理1M行(=快速),或者调用一个
MERGE
语句一百万次来处理一行(=慢得多,这是你的情况)。@MarmiteBomber有什么方法可以从python中实现吗?我只是在使用execute\u many,因为肯定会有一种方法,发布整个语句,以便逻辑可见…
clean.id