PostgreSQL UPDATE 中包含子查询的性能优化

一位网友使用update t1 set info=(select info from t2 where t1.id=t2.id) where t1.id<9999;这种查询时,发现性能很低。
而单独执行时很快的。
原因分析:
postgres=# create table t1(id int,info text);
CREATE TABLE
postgres=# create table t2(id int,info text);
CREATE TABLE

postgres=# insert into t1 select generate_series(1,10000) ;
INSERT 0 10000
postgres=# insert into t2 select generate_series(1,1000) ;
INSERT 0 1000
这个SubPlan循环了9998次,慢就慢在这里,虽然单次subquery只需要0.132毫秒,乘以9998后就是1300多毫秒了。
postgres=# explain (analyze,verbose,timing,buffers) update t1 set info=(select info from t2 where t1.id=t2.id) where t1.id<9999;
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Update on public.t1  (cost=0.00..145134.50 rows=9999 width=10) (actual time=1368.041..1368.041 rows=0 loops=1)
   Buffers: shared hit=39870
   ->  Seq Scan on public.t1  (cost=0.00..145134.50 rows=9999 width=10) (actual time=0.218..1337.192 rows=9998 loops=1)
         Output: t1.id, (SubPlan 1), t1.ctid
         Filter: (t1.id < 9999)
         Rows Removed by Filter: 2
         Buffers: shared hit=20020
         SubPlan 1
           ->  Seq Scan on public.t2  (cost=0.00..14.50 rows=1 width=32) (actual time=0.127..0.132 rows=0 loops=9998)
                 Output: t2.info
                 Filter: (t1.id = t2.id)
                 Rows Removed by Filter: 1000
                 Buffers: shared hit=19996
 Planning time: 0.095 ms
 Execution time: 1368.077 ms
(15 rows)
将SQL修改为update ... set ... from ... where ...;
LOOP消失,性能立马提升
postgres=# explain (analyze,verbose,timing,buffers) update t1 set info=t2.info from t2 where t1.id=t2.id and t1.id<9999;
                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
 Update on public.t1  (cost=24.50..221.00 rows=1000 width=48) (actual time=8.103..8.103 rows=0 loops=1)
   Buffers: shared hit=1940
   ->  Hash Join  (cost=24.50..221.00 rows=1000 width=48) (actual time=0.569..5.295 rows=1000 loops=1)
         Output: t1.id, t2.info, t1.ctid, t2.ctid
         Hash Cond: (t1.id = t2.id)
         Buffers: shared hit=26
         ->  Seq Scan on public.t1  (cost=0.00..149.00 rows=9999 width=10) (actual time=0.038..2.600 rows=9998 loops=1)
               Output: t1.id, t1.ctid
               Filter: (t1.id < 9999)
               Rows Removed by Filter: 2
               Buffers: shared hit=24
         ->  Hash  (cost=12.00..12.00 rows=1000 width=42) (actual time=0.518..0.518 rows=1000 loops=1)
               Output: t2.info, t2.ctid, t2.id
               Buckets: 1024  Batches: 1  Memory Usage: 51kB
               Buffers: shared hit=2
               ->  Seq Scan on public.t2  (cost=0.00..12.00 rows=1000 width=42) (actual time=0.025..0.240 rows=1000 loops=1)
                     Output: t2.info, t2.ctid, t2.id
                     Buffers: shared hit=2
 Planning time: 0.237 ms
 Execution time: 8.156 ms
(20 rows)

对于多个子查询的修改例子:
update u_md_rs.s_tmp_zb010s_top4_show t1
     set sal_store_num_this = (select sal_store_num_this from u_md_rs.s_tmp_zb010s_top4_show t2
                                where t1.region_no = t2.region_no
                                  and t1.region_name = t2.region_name
                                  and t2.product_code='total_sal_num'),
         inv_store_num = (select inv_store_num from u_md_rs.s_tmp_zb010s_top4_show t2
                           where t1.region_no = t2.region_no
                             and t1.region_name = t2.region_name
                             and t2.product_code='total_inv_num')
   where t1.merge_flag='top';
改为
update u_md_rs.s_tmp_zb010s_top4_show t1 set
sal_store_num_this = case when t2.product_code='total_sal_num' then t2.sal_store_num_this else t1.sal_store_num_this end ,
inv_store_num = case when t2.product_code='total_inv_num' then t2.inv_store_num else t1.inv_store_num end
from s_tmp_zb010s_top4_show t2
where t1.region_no = t2.region_no
and t1.region_name = t2.region_name
and t1.merge_flag='top'
and (t2.product_code='total_sal_num' or t2.product_code='total_inv_num');
时间: 2024-09-08 12:24:54

PostgreSQL UPDATE 中包含子查询的性能优化的相关文章

关于MYSQL DML(UPDATE DELETE)中的子查询问题和ERROR 1093 (HY000)错误

从5.6开始MYSQL的子查询进行了大量的优化,5.5中只有EXISTS strategy,在5.7中包含如下: IN(=ANY) --Semi-join   --table pullout(最快的,子查询条件为唯一键)   --first match   --semi-join materialization   --loosescan   --duplicateweedout --Materialization --EXISTS strategy(最慢的) NOT IN( <>ALL) -

详细讲述MySQL中的子查询操作_Mysql

继续做以下的前期准备工作:     新建一个测试数据库TestDB:     create database TestDB;     创建测试表table1和table2: CREATE TABLE table1 ( customer_id VARCHAR(10) NOT NULL, city VARCHAR(10) NOT NULL, PRIMARY KEY(customer_id) )ENGINE=INNODB DEFAULT CHARSET=UTF8; CREATE TABLE table

SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

原文:SQL点滴10-使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比  今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了.我从简单到复杂地写,希望高手们不要见笑.下面的sql语句设计到三个表,表的内容我用txt文件复制进去,这里不妨使用上一个随笔介绍的建立端到端的package的方法将这些表导入到数据库中,具体的就不说了. 从这里下载文件emplo

MySQL中IN子查询会导致无法使用索引

原文:MySQL中IN子查询会导致无法使用索引   今天看到一个博客园的一篇关于MySQL的IN子查询优化的案例,一开始感觉有点半信半疑(如果是换做在SQL Server中,这种情况是绝对不可能的,后面会做一个简单的测试.)随后动手按照他说的做了一个表来测试验证,发现MySQL的IN子查询做的不好,确实会导致无法使用索引的情况(IN子查询无法使用所以,场景是MySQL,截止的版本是5.7.18) MySQL的测试环境 测试表如下 create table test_table2 ( id int

在MySQL中使用子查询和标量子查询的基本操作教程_Mysql

MySQL 子查询子查询是将一个 SELECT 语句的查询结果作为中间结果,供另一个 SQL 语句调用.MySQL 支持 SQL 标准要求的所有子查询格式和操作,也扩展了特有的几种特性. 子查询没有固定的语法,一个子查询的例子如下: SELECT * FROM article WHERE uid IN(SELECT uid FROM user WHERE status=1) 对应的两个数据表如下: article 文章表: user 用户表: 查询返回结果如下所示: 在该例子中,首先通过子查询语

MySQL的子查询及相关优化学习教程_Mysql

一.子查询 1.where型子查询(把内层查询结果当作外层查询的比较条件) #不用order by 来查询最新的商品 select goods_id,goods_name from goods where goods_id = (select max(goods_id) from goods); #取出每个栏目下最新的产品(goods_id唯一) select cat_id,goods_id,goods_name from goods where goods_id in(select max(g

EntityFramework之原始查询及性能优化(六)

前言 在EF中我们可以通过Linq来操作实体类,但是有些时候我们必须通过原始sql语句或者存储过程来进行查询数据库,所以我们可以通过EF Code First来实现,但是SQL语句和存储过程无法进行映射,于是我们只能手动通过上下文中的SqlQuery和ExecuteSqlCommand来完成. SqlQuery sql语句查询实体  通过DbSet中的SqlQuery方法来写原始sql语句返回实体实例,如果是通过Linq查询返回的那么返回的对象将被上下文(context)所跟踪. 首先给出要操作

MySQL查询的性能优化

查询是数据库技术中最常用的操作.查询操作的过程比较简单,首先从客户端发出查询的SQL语句,数据库服务端在接收到由客户端发来的SQL语句后,执行这条SQL语句,然后将查询到的结果返回给客户端.虽然过程很简单,但不同的查询方式和数据库设置,对查询的性能将会有很在的影响. 因此,本文就在MySQL中常用的查询优化技术进行讨论.讨论的内容如:通过查询缓冲提高查询速度:MySQL对查询的自动优化:基于索引的排序:不可达查询的检测和使用各种查询选择来提高性能. 一. 通过查询缓冲提高查询速度 一般我们使用S

MySQL查询的性能优化基础教程

  查询是数据库技术中最常用的操作.查询操作的过程比较简单,首先从客户端发出查询的SQL语句,数据库服务端在接收到由客户端发来的SQL语句后,执行这条SQL语句,然后将查询到的结果返回给客户端.虽然过程很简单,但不同的查询方式和数据库设置,对查询的性能将会有很在的影响. 因此,本文就在MySQL中常用的查询优化技术进行讨论.讨论的内容如:通过查询缓冲提高查询速度;MySQL对查询的自动优化;基于索引的排序;不可达查询的检测和使用各种查询选择来提高性能. 一. 通过查询缓冲提高查询速度 一般我们使