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
散列连接
,并消除百万行中每一行的索引访问
以下是使用1Mid
(未显示)启动的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
散列连接
,并消除百万行中每一行的索引访问
以下是使用1Mid
(未显示)启动的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