解决postgresql insert into select无法使用并行查询的问题

本文信息基于PG13.1。

从PG9.6开始支持并行查询。PG11开始支持CREATE TABLE … AS、SELECT INTO以及CREATE MATERIALIZED VIEW的并行查询。

先说结论:

换用create table as 或者select into或者导入导出。

首先跟踪如下查询语句的执行计划:

select count(*) from test t1,test1 t2 where t1.id = t2.id ;
postgres=# explain analyze select count(*) from test t1,test1 t2 where t1.id = t2.id ;
                                    QUERY PLAN
-------------------------------------------------------------------------------------------
Finalize Aggregate (cost=34244.16..34244.17 rows=1 width=8) (actual time=683.246..715.324 rows=1 loops=1)
  -> Gather (cost=34243.95..34244.16 rows=2 width=8) (actual time=681.474..715.311 rows=3 loops=1)
     Workers Planned: 2
     Workers Launched: 2
     -> Partial Aggregate (cost=33243.95..33243.96 rows=1 width=8) (actual time=674.689..675.285 rows=1 loops=3)
        -> Parallel Hash Join (cost=15428.00..32202.28 rows=416667 width=0) (actual time=447.799..645.689 rows=333333 loops=3)
           Hash Cond: (t1.id = t2.id)
           -> Parallel Seq Scan on test t1 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.025..74.010 rows=333333 loops=3)
           -> Parallel Hash (cost=8591.67..8591.67 rows=416667 width=4) (actual time=260.052..260.053 rows=333333 loops=3)
              Buckets: 131072 Batches: 16 Memory Usage: 3520kB
              -> Parallel Seq Scan on test1 t2 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.032..104.804 rows=333333 loops=3)
 Planning Time: 0.420 ms
 Execution Time: 715.447 ms
(13 rows)

可以看到走了两个Workers。

下边看一下insert into select:

postgres=# explain analyze insert into va select count(*) from test t1,test1 t2 where t1.id = t2.id ;
                                  QUERY PLAN
-------------------------------------------------------------------------------------------
Insert on va (cost=73228.00..73228.02 rows=1 width=4) (actual time=3744.179..3744.187 rows=0 loops=1)
  -> Subquery Scan on "*SELECT*" (cost=73228.00..73228.02 rows=1 width=4) (actual time=3743.343..3743.352 rows=1 loops=1)
     -> Aggregate (cost=73228.00..73228.01 rows=1 width=8) (actual time=3743.247..3743.254 rows=1 loops=1)
        -> Hash Join (cost=30832.00..70728.00 rows=1000000 width=0) (actual time=1092.295..3511.301 rows=1000000 loops=1)
           Hash Cond: (t1.id = t2.id)
           -> Seq Scan on test t1 (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.030..421.537 rows=1000000 loops=1)
           -> Hash (cost=14425.00..14425.00 rows=1000000 width=4) (actual time=1090.078..1090.081 rows=1000000 loops=1)
              Buckets: 131072 Batches: 16 Memory Usage: 3227kB
              -> Seq Scan on test1 t2 (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.021..422.768 rows=1000000 loops=1)
 Planning Time: 0.511 ms
 Execution Time: 3745.633 ms
(11 rows)

可以看到并没有Workers的指示,没有启用并行查询。

即使开启强制并行,也无法走并行查询。

postgres=# set force_parallel_mode =on;
SET
postgres=# explain analyze insert into va select count(*) from test t1,test1 t2 where t1.id = t2.id ;
                                  QUERY PLAN
-------------------------------------------------------------------------------------------
Insert on va (cost=73228.00..73228.02 rows=1 width=4) (actual time=3825.042..3825.049 rows=0 loops=1)
  -> Subquery Scan on "*SELECT*" (cost=73228.00..73228.02 rows=1 width=4) (actual time=3824.976..3824.984 rows=1 loops=1)
     -> Aggregate (cost=73228.00..73228.01 rows=1 width=8) (actual time=3824.972..3824.978 rows=1 loops=1)
        -> Hash Join (cost=30832.00..70728.00 rows=1000000 width=0) (actual time=1073.587..3599.402 rows=1000000 loops=1)
           Hash Cond: (t1.id = t2.id)
           -> Seq Scan on test t1 (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.034..414.965 rows=1000000 loops=1)
           -> Hash (cost=14425.00..14425.00 rows=1000000 width=4) (actual time=1072.441..1072.443 rows=1000000 loops=1)
              Buckets: 131072 Batches: 16 Memory Usage: 3227kB
              -> Seq Scan on test1 t2 (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.022..400.624 rows=1000000 loops=1)
 Planning Time: 0.577 ms
 Execution Time: 3825.923 ms
(11 rows)

原因在官方文档有写:

The query writes any data or locks any database rows. If a query contains a data-modifying operation either at the top level or within a CTE, no parallel plans for that query will be generated. As an exception, the commands CREATE TABLE … AS, SELECT INTO, and CREATE MATERIALIZED VIEW which create a new table and populate it can use a parallel plan.

解决方案有如下三种:

1.select into

postgres=# explain analyze select count(*) into vaa from test t1,test1 t2 where t1.id = t2.id ;
                                    QUERY PLAN
-------------------------------------------------------------------------------------------
Finalize Aggregate (cost=34244.16..34244.17 rows=1 width=8) (actual time=742.736..774.923 rows=1 loops=1)
  -> Gather (cost=34243.95..34244.16 rows=2 width=8) (actual time=740.223..774.907 rows=3 loops=1)
     Workers Planned: 2
     Workers Launched: 2
     -> Partial Aggregate (cost=33243.95..33243.96 rows=1 width=8) (actual time=731.408..731.413 rows=1 loops=3)
        -> Parallel Hash Join (cost=15428.00..32202.28 rows=416667 width=0) (actual time=489.880..700.830 rows=333333 loops=3)
           Hash Cond: (t1.id = t2.id)
           -> Parallel Seq Scan on test t1 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.033..87.479 rows=333333 loops=3)
           -> Parallel Hash (cost=8591.67..8591.67 rows=416667 width=4) (actual time=266.839..266.840 rows=333333 loops=3)
              Buckets: 131072 Batches: 16 Memory Usage: 3520kB
              -> Parallel Seq Scan on test1 t2 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.058..106.874 rows=333333 loops=3)
 Planning Time: 0.319 ms
 Execution Time: 783.300 ms
(13 rows)

2.create table as

postgres=# explain analyze create table vb as select count(*) from test t1,test1 t2 where t1.id = t2.id ;
                                   QUERY PLAN
-------------------------------------------------------------------------------------------
 Finalize Aggregate (cost=34244.16..34244.17 rows=1 width=8) (actual time=540.120..563.733 rows=1 loops=1)
  -> Gather (cost=34243.95..34244.16 rows=2 width=8) (actual time=537.982..563.720 rows=3 loops=1)
     Workers Planned: 2
     Workers Launched: 2
     -> Partial Aggregate (cost=33243.95..33243.96 rows=1 width=8) (actual time=526.602..527.136 rows=1 loops=3)
        -> Parallel Hash Join (cost=15428.00..32202.28 rows=416667 width=0) (actual time=334.532..502.793 rows=333333 loops=3)
           Hash Cond: (t1.id = t2.id)
           -> Parallel Seq Scan on test t1 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.018..57.819 rows=333333 loops=3)
           -> Parallel Hash (cost=8591.67..8591.67 rows=416667 width=4) (actual time=189.502..189.503 rows=333333 loops=3)
              Buckets: 131072 Batches: 16 Memory Usage: 3520kB
              -> Parallel Seq Scan on test1 t2 (cost=0.00..8591.67 rows=416667 width=4) (actual time=0.023..77.786 rows=333333 loops=3)
 Planning Time: 0.189 ms
 Execution Time: 565.448 ms
(13 rows)

3.或者通过导入导出的方式,例如:

psql -h localhost -d postgres -U postgres -c "select count(*) from test t1,test1 t2 where t1.id = t2.id " -o result.csv -A -t -F ","
psql -h localhost -d postgres -U postgres -c "COPY va FROM 'result.csv' WITH (FORMAT CSV, DELIMITER ',', HEADER FALSE, ENCODING 'windows-1252')"

一些场景下也会比非并行快。

补充:POSTGRESQL: 动态SQL语句中不能使用SELECT INTO?

我的数据库版本是 PostgreSQL 8.4.7 。 下面是出错的存储过程:

CREATE or Replace FUNCTION func_getnextid(
  tablename varchar(240),
  idname varchar(20) default 'id')
RETURNS integer AS $funcbody$
Declare
  sqlstring varchar(240);
  currentId integer;
Begin
  sqlstring:= 'select max("' || idname || '") into currentId from "' || tablename || '";';
  EXECUTE sqlstring;
  if currentId is NULL or currentId = 0 then
    return 1;
  else
    return currentId + 1;
  end if;
End;
$funcbody$ LANGUAGE plpgsq

执行后出现这样的错误:

SQL error:

ERROR: EXECUTE of SELECT ... INTO is not implemented

CONTEXT: PL/pgSQL function "func_getnextbigid" line 6 at EXECUTE statement

改成这样的就对了:

CREATE or Replace FUNCTION func_getnextid(
  tablename varchar(240),
  idname varchar(20) default 'id')
RETURNS integer AS $funcbody$
Declare
  sqlstring varchar(240);
  currentId integer;
Begin
  sqlstring:= 'select max("' || idname || '") from "' || tablename || '";';
  EXECUTE sqlstring into currentId;
  if currentId is NULL or currentId = 0 then
    return 1;
  else
    return currentId + 1;
  end if;
End;
$funcbody$ LANGUAGE plpgsql;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 解决postgresql无法远程访问的情况

    今天刚入手这个数据库玩玩,发现无法通过IP去访问数据库,后面查询原因为,该数据库默认只能通过本地连接,也就是回环地址(127.0.0.1) 解决方案: 1.修改安装目录下的data\pg_hba.conf,在配置文件最后有IPV4和IPV6的配置,新增一行(这里我用的IPV4,开放所有IP) host all all 0.0.0.0/0 md5 说明: 该配置为允许所有IP访问,下面有对应的一些配置示例提供参考 32 -> 192.168.1.1/32 表示必须是来自这个IP地址的访问才合法:

  • postgresql修改完端口后直接psql连接数据库报错的解决

    今天修改pg的端口号port改成5435后重启完数据库的时候直接psql进库的时候进不去 [postgres@node2 data]$ psql psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.5432 这时,进数据库有两种方式 1.psq

  • 浅谈PostgreSQL中的孤儿文件用法(orphaned data files)

    创建一个测试表 postgres=# create table t1(a int); CREATE TABLE postgres=# select pg_relation_filepath('t1'); pg_relation_filepath ---------------------- base/75062/75297 (1 row) postgres=# 在操作系统上已经可以看到该文件. $ ls -la $PGDATA/base/75062/75297 -rw------- 1 post

  • postgresql 实现启动、状态查看、关闭

    利用psql启动数据库 [postgres@highgo ~]$ pg_ctl start 查看系统中运行的postgres进程 #ps -ef | grep postgres 连接postgresql数据库 #psql -h 127.0.0.1 -d postgres -U postgres 停止postgresql数据库实例 #pg_ctl stop #ps -ef | grep postgres 启动服务器最简单的方法是像下面这样: $ postgres -D /usr/local/pgs

  • postgresql连续归档及时间点恢复的操作

    简介 前面我们介绍了通过pgsql的流复制在生产环境中搭建高可用环境来保证服务的可持续性:我们也要对数据库进行周期备份,来防止数据的丢失,这就需要连续归档,它不仅可以用于大型数据库的增量备份和恢复,也可以用于搭建standby镜像备份.    PostgreSQL默认处于非归档模式.开启归档模式,主要涉及到三个参数:wal_level,archive_mode和archive_commandwal_level参数默认为mininal,设置此参数为archive或者之上的级别都可以打开归档.当po

  • 浅谈Postgresql默认端口5432你所不知道的一点

    关于Postgresql端口5432的定义: 5432端口,已经在IANA(The Internet Assigned Numbers Authority,互联网数字分配机构)注册, 并把该端口唯一分配给Postgres. 这意味着,一台安装了linux OS的服务器,哪怕没有安装过postgresql数据库,也会有这个预留端口. 查看这个预留端口的方法如下: new@newdb-> cat /etc/services |grep 5432 postgres 5432/tcp postgresq

  • PostgreSQL 启动失败的解决方案

    环境 Red Hat CloudForms 4.x 问题 postgresql 启动失败,并导致evmserverd崩溃. [----] I, [2016-11-29T03:12:31.816753 #1201:e4f994] INFO -- : MIQ(PostgresAdmin.runcmd_with_logging) Running command... service rh-postgresql94-postgresql start [----] E, [2016-11-29T03:12

  • PostgreSQL 对IN,EXISTS,ANY/ALL,JOIN的sql优化方案

    测试环境: postgres=# select version(); version --------------------------------------------------------------------------------------------------------- PostgreSQL 11.9 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-b

  • 解决postgresql insert into select无法使用并行查询的问题

    本文信息基于PG13.1. 从PG9.6开始支持并行查询.PG11开始支持CREATE TABLE - AS.SELECT INTO以及CREATE MATERIALIZED VIEW的并行查询. 先说结论: 换用create table as 或者select into或者导入导出. 首先跟踪如下查询语句的执行计划: select count(*) from test t1,test1 t2 where t1.id = t2.id ; postgres=# explain analyze se

  • postgresql insert into select无法使用并行查询的解决

    本文信息基于PG13.1. 从PG9.6开始支持并行查询.PG11开始支持CREATE TABLE - AS.SELECT INTO以及CREATE MATERIALIZED VIEW的并行查询. 先说结论: 换用create table as 或者select into或者导入导出. 首先跟踪如下查询语句的执行计划: select count(*) from test t1,test1 t2 where t1.id = t2.id ; postgres=# explain analyze se

  • postgresql 13.1 insert into select并行查询的实现

    本文信息基于PG13.1. 从PG9.6开始支持并行查询.PG11开始支持CREATE TABLE - AS.SELECT INTO以及CREATE MATERIALIZED VIEW的并行查询. 先说结论: 换用create table as 或者select into或者导入导出. 首先跟踪如下查询语句的执行计划: select count(*) from test t1,test1 t2 where t1.id = t2.id ; postgres=# explain analyze se

  • 解决MySQL读写分离导致insert后select不到数据的问题

    MySQL设置独写分离,在代码中按照如下写法,可能会出现问题 // 先录入 this.insert(obj); // 再查询 Object res = this.selectById(obj.getId()); res: null; 线上的一个坑,做了读写分离以后,有一个场景因为想方法复用,只传入一个ID就好,直接去库里查出一个对象再做后续处理,结果查不出来,事务隔离级别各种也都排查了,最后发现是读写分离的问题,所以换个思路去实现吧. 补充知识:MySQL INSERT插入条件判断:如果不存在则

  • Oracle数据库并行查询出错的解决方法

    Oracle的并行查询是使用多个操作系统级别的Server Process来同时完成一个SQL查询,本文讲解Oracle数据库并行查询出错的解决方法如下: 1.错误描述 ORA-12801: 并行查询服务器P007中发出错误信号 ORA-01722:无效数字 12801.00000 -"error signaled in parallel query server %s" *Cause: A parallel query server reached an exception cond

  • mybatisplus的坑 insert标签insert into select无参数问题的解决

    目录 mybatisplus的坑 insert标签insert into select无参数 insert into select语句的坑 事故发生的经过 事故还原 出现的原因 解决方案 最终的sql 小结一下 mybatisplus的坑 insert标签insert into select无参数 实际项目中发现 <insert id="xxx"> insert into xxxx select xxxx </insert> 会报错 org.mybatis.sp

  • Oracle并行操作之并行查询实例解析

    Oracle数据库的并行操作特性,其本质上就是强行榨取除数据库服务器空闲资源(主要是CPU资源),对一些高负荷大数据量数据进行分治处理.并行操作是一种非确定性的优化策略,在选择的时候需要小心对待.目前,使用并行操作特性的主要有下面几个方面: Parallel Query:并行查询,使用多个操作系统级别的Server Process来同时完成一个SQL查询: Parallel DML:并行DML操作.类似于Parallel Query.当要对大数据量表进行DML操作,如insert.update和

  • 解决postgresql 数据库 update更新慢的原因

    ;大约140000条数据) 竟然运行了一个小时还没有完成 下面是我的几点解决方案 我的update 语句 是从一个临时表更新值到另一个正式表 因为具体数据需要保密,我就不截图了 只说说大体思路,与方法 1.查看语句是否有问题 复制俩个一模一样的表 和数据 手动执行语句 发现不到一分钟就运行成功了 这样就可以确认语句没有问题 2.查找影响updata的因素 我的第一反应是不是有锁 有锁的情况会导致等待或者死锁 查询锁 select w1.pid as 等待进程, w1.mode as 等待锁模式,

  • 解析MySQL中INSERT INTO SELECT的使用

    1. 语法介绍有三张表a.b.c,现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段.对于这种情况,可以使用如下的语句来实现:INSERT INTO db1_name (field1,field2) SELECT field1,field2 FROM db2_name 上面的语句比较适合两个表的数据互插,如果多个表就不适应了.对于多个表,可以先将需要查询的字段JOIN起来,然后组成一个视图后再SELECT FROM就可以了: INSERT INTO a (field1,field2)

  • 数据库插入数据之select into from与insert into select区别详解

    可能第一次接触select...into...from...和insert into...select...有很多人都会误解, 从表面上看都是把相关信息查询出来,然后添加到一个表里,其实还远远没有这么简单,接下来,小猪就用最普通的表述给大家介绍一下这两者间的区别. 步骤/方法 1.首先,我们来看一下insert into select语句,其语法形式为:Insert into Table2(field1,field2,...) select value1,value2,... from Tabl

随机推荐