PostgreSQL使用函数的多表关联视图在排序时的性能问题

一、问题描述

近日PostgreSQL的某个表的记录数由万级增加到一百万级(设计能力是一亿)时,建立在该表之上的某个多表关联VIEW的查询性能急剧变慢(大约从10ms级跃升到100s级)。经分析查询计划,发现瓶颈在于排序用时很长;而排序用时的诱因是什么?在排除掉一个个其它因素后,发现是VIEW定义中使用了函数(非内部函数,特此说明)。在将自定义函数更改为等效的子查询或连接查询时,性能得到很好的改善。

因为实际的表、VIEW、函数都过于复杂,为描述及重现问题的关键,以下将表、VIEW、函数等都进行简化,。

二、测试对象

创建三个测试用表:

create table t1
(
  id int not null primary key,
  name varchar(20)
);

create table t2
(
  id int not null primary key,
  name varchar(20)
);

create table t3
(
  id int not null primary key,
  name varchar(20)
);

再创建函数、包含它的VIEW、作为对比的等效VIEW:

create or replace function f1(p_id in int)
  returns int as $$
  declare v_name varchar(40);
begin
  select name3 into v_name from t3 where id=p_id;
  if v_name is null then return 0; else return length(v_name); end if;
end;
$$ language plpgsql;

create view v1 as
  select t1.id id, t1.name name1, t2.name name2, f1(t1.id) length
  from t1 left join t2 on t2.id=t1.id;

create view v2 as
    select t1.id id, t1.name1 name1, t2.name2 name2,
      coalesce(length(t3.name3), 0) length
    from t1 left join t2 on t2.id=t1.id left join t3 on t3.id=t1.id;

最后向表t1插入8000条记录,id为1..8000,name的值则无所谓;再分别拷贝部分数据到表t2、t3:

insert into t2 select * from t1 where t1.id%2=0;
insert into t3 select * from t1 where t1.id%3=0;

三、检查执行计划

完成所有准备工作后,检查在两个VIEW上排序查询的执行计划:

显然,排序用时是大头,而v1在排序上的用时差不多是v2的3倍。

再进一步测试,如果加上limit ... offset(常跟order by一起用于分页),两个VIEW的差距更加明显:

如果去掉排序操作,v1的查询用时也会多于v2,但相比之前少差不多一个数量级。限于篇幅,这里不贴图了。

本次测试的记录数还不到万级,已经可以看出两种VIEW的差距,有兴趣的同行可以自行验证表记录数在十万级及更多以上的情况。

四、结论

根据本次简单测试,并结合实践中的情况(抱歉不能给出详情),得出以下结论:

  1. PostgreSQL中,如果多表关联VIEW中包使用了函数,尽量修改为子查询或连接查询;
  2. 对于排序操作,含函数的VIEW的性能远低于等效的子查询或连接查询的VIEW,如再含有分页操作,两者的性能差距更大;
  3. 实践中,当主表记录数达到一定数量(临界值未知),含函数的VIEW的排序甚至无法利用索引而走全表扫描,从而引发用时剧增;
  4. 以前的实践中,Oracle中两种VIEW的差别并不是十分明显。

原文地址:https://www.cnblogs.com/wggj/p/8360228.html

时间: 2024-10-11 02:40:48

PostgreSQL使用函数的多表关联视图在排序时的性能问题的相关文章

PostgreSQL对现有,新建的表和视图授权给用户

由于开发提出需求: (1)在多个PostgreSQL的instacne上面创建一个readonly用户,仅对数据库里面的表或者视图(包括物化视图)有仅有select权限,并且对以后新建的表和视图也要有select权限,我们知道PostgreSQL 在schema下新建的表,对于一个已经存在的用户不会自动赋予select的权限的,需要我们使用grant select...手动去执行,这样就比较麻烦,总不能每次新建表,我们就赋权一次,要知道我们有很多实例,总不能把时间都放在这样没有       意义

sql:除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询

执行sql语句: select * from ( select * from tab where ID>20 order by userID desc ) as a order by date desc 逻辑上看着挺对 但是报错: 除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图.内联函数.派生表.子查询和公用表表达式中无效.   只要我们在嵌套子查询视图里面加入: top 100 percent 即可 select * from ( select top 100

Oracle中关联表的视图创建

这几天的工作基本上没有了比较的新的技术点,就是反反复复的修改需求,修改Bug--当然,也是到了此刻,自己猜觉得在一个庞大的项目中,需求分析的重要性,以及需求说明书的重要性.我们在需求模糊.文档缺乏的条件下,反复修改功能已经成了家常便饭,今天领导说这个功能应该这样,我们就要立刻改到这样,第二天领导说又要原来的那样,我们只能再改回去了--有时候,我们也曾调侃自己是典型的面向领导开发-- 今天没有什么比较新的技术点来总结了,自己回顾了一下,这几天的工作,发现在关联表中创建视图的时候对于连接不是特别熟悉

多表关联时视图查出重复数据问题

多表关联时本身有一条数据,但是视图查出重复数据用distinct可以解决. 如: 视图如下 SELECT DISTINCT t1.station_id as station_id, t1.tick_sn as tick_sn, t1.order_id as order_id, t2.station_name as station_name, t3.game_id as game_id, FROM electric_lottery_report_info t1LEFT JOIN electric_

SQL SERVER2008 存储过程、表、视图、函数的权限

EXEC sp_addrolemember N'db_owner', N'db'----将db 设置为 db_owner 角色中的一员 EXEC sp_droprolemember N'db_owner', N'db'----将db 从 db_owner 角色 去除 ALTER AUTHORIZATION ON SCHEMA::[db_datareader] TO dbs  ----给db 赋予 拥有 db_datareader 架构 ALTER AUTHORIZATION ON SCHEMA:

SQL 关联两个表的视图总结

视图就是一条select查询语句,是一张虚拟表. table a  , table b  以表a基表(a LEFT  JOIN b) 1.1 当update view时 更新view中表b字段,可执行,并且b表随之改变. 当update view时 更新view中表a字段,可执行,并且a表随之改变. 当update view时 更新view中表a和表b,不可执行. 总结:更新view时 只能更新单一表字段,对应表随之改变. 1.2 当update 表a时 更新表a中view对应的字段时,可执行,

oracle表,视图,存储过程,函数,序列.....查询

查询存储过程,函数,序列,表,视图的名字 select object_name from user_objects where object_type = 'PROCEDURE' select object_name from user_objects where object_type = 'FUNCTION' select object_name from user_objects where object_type = 'SEQUENCE' select object_name from

Oracle组函数、多表查询、集合运算、数据库对象(序列、视图、约束、索引、同义词)等

count组函数:(过滤掉空的字段) select count(address),count(*) from b_user max() avg() min(),sum() select sum(age),max(age),min(age),avg(nvl(age,0)) from b_user 1       260     70      10      37.1428571428571 group by:如果前面定义了该字段名  则groupby必须也写上该字段 select name,pw

Oracle创建两表关联查询的视图

在项目开发中,有时候会用到多表查询,有很多种方法,比如关联,比如视图,但对于查询来说,视图查询是最快的,如果你的数据库的字段信息很多,那查询就得整表查,比如两表查询,我们就可以把要的字段抽取出来,放在视图中,这样查询时就只要查询视图中所要的字段,其他的就可以无视.下面我记录一下Oracle创建视图 大多人操作数据库是用Scott权限进行操作数据库,但Scott是没有创建视图的权限的,所以我们要进入管理员System账号,进去给Scott授权一个创建视图权限.进入System后,我们打入以下语句