快速阅读请从第3节开始。
01
创建测试表
sql
drop table if exists deppeoples;drop table if exists departments;drop type if exists deppeoples01;/****************************************************************************************部门表****************************************************************************************/create table departments(objectid serial not null, --唯一编号parentid integer not null, --上级部门,指向本表的objectid,0表示最顶级部门name text not null, --部门名称describe text, --部门备注generate timestamptz default(now()) not null, --创建时间state integer default(2) not null, --状态.0已无效,(1<<1)正常constraint pk_departments_objectid primary key(objectid) with (fillfactor=80)) with (fillfactor=80);create index idx_departments_parentid on departments(parentid) with (fillfactor=80);/****************************************************************************************部门人员表****************************************************************************************/create table deppeoples(objectid bigserial not null, --唯一编号depid integer not null, --部门编号,外键(departments->objectid,级联删除)name text not null, --姓名title integer not null, --职务.来自字典,测试数据用1-10分别表示,数据越大职务越高tel text not null, --联系电话sex integer not null, --性别.来自字典,测试数据随机生成national integer not null, --民族.来自字典mail text, --邮箱describe text, --备注generate timestamptz default(now()) not null, --创建时间state integer default(2) not null, --状态.0已无效,(1<<1)正常constraint pk_deppeoples_objectid primary key(objectid) with (fillfactor=80),constraint fk_deppeoples_contid foreign key(depid) references departments(objectid) on delete cascade) with (fillfactor=80);create index idx_deppeoples_depid on deppeoples(depid,title) with (fillfactor=80);```
02
测试数据
sql
insert into departments(parentid,name) values(0,'xxxxxx集团公司');insert into departments(parentid,name)select1 as parentid,(random()*(1546272000-1514736000)+1514736000)::bigint as namefrom generate_series(1,999);```
2.2 部门人员测试数据
创建100万部门人员,随机分布在各个部门,人员名称在数据1514736000-1546272000之间随机生成。同时每个部门的最高领导只有1人。
sql
do $$declarev_start bigint;v_end bigint;beginfor i in 1..1000 loopv_start := (i-1)*1000 + 1;v_end := v_start + 999;insert into deppeoples(depid,name,title,tel,sex,national)select(random()*(100-1)+1)::integer as depid,(random()*(1546272000-1514736000)+1514736000)::bigint as name,(random()*(9-1)+1)::integer as title,(random()*(13999999999-13000000000)+13000000000)::bigint as tel,(random()*(3-1)+1)::integer as sex,(random()*(54-1)+1)::integer as nationalfrom generate_series(v_start,v_end);raise notice '%,%', v_start,v_end;end loop;end;$$;```
2.3 生成每个部门的最高领导
sql
insert into deppeoples(depid,name,title,tel,sex,national)selectobjectid as depid,(random()*(1546272000-1514736000)+1514736000)::bigint as name,10 as title,(random()*(13999999999-13000000000)+13000000000)::bigint as tel,(random()*(3-1)+1)::integer as sex,(random()*(54-1)+1)::integer as nationalfrom departments;```
为保证测试的准确性,生成完成后运行vacuum。
sql
vacuum freeze verbose analyze departments;vacuum freeze verbose analyze deppeoples;```
03
查询各部门的最高领导
3.1 join方式
sql
--禁用并行set max_parallel_workers_per_gather=0;explain (analyze,verbose,costs,buffers,timing)selectt1.name as department,t2.name,t2.title,t2.telfrom departments as t1left join deppeoples as t2 on t2.depid=t1.objectidwhere t2.title=10;```执行5次,取最后一次,可以看到left join共扫描了3012页,用时3.296 ms```bashQUERY PLAN-----------------------------------------------------------------------------------------------------------------------------------------------------Nested Loop (cost=0.42..7796.00 rows=1 width=38) (actual time=3.257..3.257 rows=0 loops=1)Output: t1.name, t2.name, t2.title, t2.telBuffers: shared hit=3012-> Seq Scan on public.departments t1(cost=0.00..21.00 rows=1000 width=15)(actual time=0.009..0.200 rows=1000 loops=1)Output: t1.objectid, t1.parentid, t1.name, t1.describe, t1.generate, t1.stateBuffers: shared hit=11-> Index Scan using idx_deppeoples_depid on public.deppeoples t2(cost=0.42..7.76 rows=1 width=31)(actual time=0.003..0.003 rows=0 loops=1000)Output: t2.objectid, t2.depid, t2.name, t2.title, t2.tel, t2.sex, t2."national",t2.mail, t2.describe, t2.generate, t2.stateIndex Cond: ((t2.depid = t1.objectid) AND (t2.title = 10))Buffers: shared hit=3001Planning Time: 0.314 msExecution Time: 3.296 ms(12 rows)```
sql
--重点创建row类型,定义输入的列名称和类型drop type if exists deppeoples01;create type deppeoples01 as (name1 text,title1 integer,tel1 text);explain (analyze,verbose,costs,buffers,timing)with cte as(selectt1.name as department,(select row(name,title,tel)::deppeoples01 as r from deppeoples as t2 wheret2.depid=t1.objectid and title=10 order by objectid desc limit 1)from departments as t1)select department,(r).name1,(r).title1,(r).tel1 from cte;```执行5次,取最后一次,可以看到子查询共扫描了3012页,用时8.827 ms```bashQUERY PLAN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------CTE Scan on cte (cost=8481.00..8501.00 rows=1000 width=100) (actual time=0.042..8.584 rows=1000 loops=1)Output: cte.department, (cte.r).name1, (cte.r).title1, (cte.r).tel1Buffers: shared hit=3012CTE cte-> Seq Scan on public.departments t1 (cost=0.00..8481.00 rows=1000 width=43) (actual time=0.036..7.363 rows=1000 loops=1)Output: t1.name, (SubPlan 1)Buffers: shared hit=3012SubPlan 1-> Limit (cost=8.46..8.46 rows=1 width=40) (actual time=0.006..0.006 rows=0 loops=1000)Output: (ROW(t2.name, t2.title, t2.tel)::deppeoples01), t2.objectidBuffers: shared hit=3001-> Sort (cost=8.46..8.46 rows=1 width=40) (actual time=0.005..0.005 rows=0 loops=1000)Output: (ROW(t2.name, t2.title, t2.tel)::deppeoples01), t2.objectidSort Key: t2.objectid DESCSort Method: quicksort Memory: 25kBBuffers: shared hit=3001-> Index Scan using idx_deppeoples_depid on public.deppeoples t2(cost=0.42..8.45 rows=1 width=40)(actual time=0.003..0.003 rows=0 loops=1000)Output: ROW(t2.name, t2.title, t2.tel)::deppeoples01, t2.objectidIndex Cond: ((t2.depid = t1.objectid) AND (t2.title = 10))Buffers: shared hit=3001Planning Time: 0.237 msExecution Time: 8.827 ms(22 rows)```
04
小结
I Love PG
关于我们
中国开源软件推进联盟PostgreSQL分会(简称:PG分会)于2017年成立,由国内多家PG生态企业所共同发起,业务上接受工信部产业发展研究院指导。PG分会致力于构建PG产业生态,推动PG产学研用发展,是国内一家PG行业协会组织。
技术文章精彩回顾 PostgreSQL学习的九层宝塔 PostgreSQL职业发展与学习攻略 搞懂PostgreSQL数据库透明数据加密之加密算法介绍 一文读懂PostgreSQL-12分区表 PostgreSQL源码学习之:RegularLock Postgresql源码学习之词法和语法分析 PostgreSQL buffer管理 最佳实践—PG数据库系统表空间重建 PostgreSQL V12中的流复制配置 2019,年度数据库舍 PostgreSQL 其谁? PostgreSQL使用分片(sharding)实现水平可扩展性 一文搞懂PostgreSQL物化视图 PostgreSQL原理解析之:PostgreSQL备机是否做checkpoint PostgreSQL复制技术概述 PG活动精彩回顾 见证精彩|PostgresConf.CN2019大会盛大开幕 PostgresConf.CN2019大会DAY2|三大分论坛,精彩不断 PostgresConf.CN2019培训日|爆满!Training Day现场速递! 「PCC-Training Day」培训日Day2圆满结束,PCC2019完美收官 创建PG全球生态!PostgresConf.CN2019大会盛大召开 首站起航!2019“让PG‘象’前行”上海站成功举行 走进蓉城丨2019“让PG‘象’前行”成都站成功举行 中国PG象牙塔计划发布,首批合作高校授牌仪式在天津举行 PostgreSQL实训基地落户沈阳航空航天大学和渤海大学,高校数据库课改正当时 群英论道聚北京,共话PostgreSQL 相聚巴厘岛| PG Conf.Asia 2019 DAY0、DAY1简报 相知巴厘岛| PG Conf.Asia 2019 DAY2简报 相惜巴厘岛| PG Conf.Asia 2019 DAY3简报 独家|硅谷Postgres大会简报 全球规模最大的PostgreSQL会议等你来! PG培训认证精彩回顾 关于中国PostgreSQL培训认证,你想知道的都在这里! 首批中国PGCA培训圆满结束,首批认证考试将于10月18日和20日举行! 中国首批PGCA认证考试圆满结束,203位考生成功获得认证! 中国第二批PGCA认证考试圆满结束,115位考生喜获认证! 请查收:中国首批PGCA证书! 重要通知:三方共建,中国PostgreSQL认证权威升级! 一场考试迎新年 | 12月28日,首次PGCE中级认证考试开考! 近500人参与!首次PGCE中级、第三批次PGCA初级认证考试落幕!
最后修改时间:2020-03-24 08:59:31
文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。





