Greenplum优化--SQL调优篇


目录

  • 数据库查询预准备

    • VACUUM
    • ANALYZE
    • EXPLAIN执行计划
    • 两种聚合方式
    • 关联
    • 重分布
  • 查询优化
    • explain参数
    • 选择合适分布键
    • 分区表
    • 压缩表
    • 分组扩展
    • 窗口函数
    • 列存储和行存储
    • 函数和存储过程
    • 索引使用
    • NOTIN
    • 聚合函数太多
    • 资源队列
    • 其它优化技巧
  • 参考

数据库查询预准备

VACUUM

  • vacuum只是简单的回收空间且令其可以再次使用,没有请求排它锁,仍旧可以对表读写
  • vacuum full执行更广泛的处理,包括跨块移动行,以便把表压缩至使用最少的磁盘块数目存储。相对vacuum要慢,而且会请求排它锁。
  • 定期执行:在日常维护中,需要对数据字典定期执行vacuum,可以每天在数据库空闲的时候进行。然后每隔一段较长时间(两三个月)对系统表执行一次vacuum full,这个操作需要停机,比较耗时,大表可能耗时几个小时。
  • reindex:执行vacuum之后,最好对表上的索引进行重建

ANALYZE

  • 命令:analyze [talbe [(column,..)]]
  • 收集表内容的统计信息,以优化执行计划。如创建索引后,执行此命令,对于随即查询将会利用索引。
  • 自动统计信息收集
  • 在postgresql.conf中有控制自动收集的参数gp_autostats_mode设置,gp_autostats_mode三个值:none、no_change、on_no_stats(默认)
    • none:禁止收集统计信息
    • on change:当一条DML执行后影响的行数超过gp_autostats_on_change_threshold参数指定的值时,会执行完这条DML后再自动执行一个analyze 的操作来收集表的统计信息。
    • no_no_stats:当使用create talbe as select 、insert 、copy时,如果在目标表中没有收集过统计信息,那么会自动执行analyze 来收集这张表的信息。gp默认使用on_no_stats,对数据库的消耗比较小,但是对于不断变更的表,数据库在第一次收集统计信息之后就不会再收集了。需要人为定时执行analyze.
  • 如果有大量的运行时间在1分钟以下的SQL,你会发现大量的时间消耗在收集统计信息上。为了降低这一部分的消耗,可以指定对某些列不收集统计信息,如下所示:
    1. create table test(id int, name text,note text);
    

    上面是已知道表列note不需出现在join列上,也不会出现在where语句的过滤条件下,因为可以把这个列设置为不收集统计信息:

    1. alter table test alter note SET STATISTICS 0;
    

EXPLAIN执行计划

显示规划器为所提供的语句生成的执行规划。

  • cost:返回第一行记录前的启动时间, 和返回所有记录的总时间(以磁盘页面存取为

    单位计量)

  • rows:根据统计信息估计SQL返回结果集的行数
  • width:返回的结果集的每一行的长度,这个长度值是根据pg_statistic表中的统计信息

    来计算的。

两种聚合方式

  • hashaggregate

    根据group by字段后面的值算出hash值,并根据前面使用的聚合函数在内存中维护对应的列表,几个聚合函数就有几个数组。相同数据量的情况下,聚合字段的重复度越小,使用的内存越大。

  • groupaggregate

    先将表中的数据按照group by的字段排序,在对排好序的数据进行全扫描,并进行聚合函数计算。消耗内存基本是恒定的。

  • 选择

    在SQL中有大量的聚合函数,group by的字段重复值比较少的时候,应该用groupaggregate

关联

分为三类:hash join、nestloop join、merge join,在保证sql执行正确的前提下,规划器优先采用hash join。

  • hash join: 先对其中一张关联的表计算hash值,在内存中用一个散列表保存,然后对另外一张表进行全表扫描,之后将每一行与这个散列表进行关联。
  • nestedloop:关联的两张表中的数据量比较小的表进行广播,如笛卡尔积:select * fromtest1,test2
  • merge join:将两张表按照关联键进行排序,然后按照归并排序的方式将数据进行关联,效率比hash join差。full outer join只能采用merge join来实现。
  • 关联的广播与重分布解析P133,一般规划器会自动选择最优执行计划。
  • 有时会导致重分布和广播,比较耗时的操作

重分布

一些sql查询中,需要数据在各节点重新分布,受制于网络传输、磁盘I/O,重分布的速度比较慢。

  • 关联键强制类型转换

    一般,表按照指定的分布键作hash分部。如果两个表按照id:intege、id:numericr分布,关联时,需要有一个表id作强制类型转化,因为不同类型的hash值不一样,因而导致数据重分布。

  • 关联键与分部键不一致
  • group by、开窗函数、grouping sets会引发重分布

查询优化

通过explain观察执行计划,从而确定如果优化SQL。

explain参数

显示规划器为所提供的语句生成的执行规划。

  • cost:返回第一行记录前的启动时间, 和返回所有记录的总时间(以磁盘页面存取为单位计量)
  • rows:根据统计信息估计SQL返回结果集的行数
  • width:返回的结果集的每一行的长度,这个长度值是根据pg_statistic表中的统计信息来计算的。

选择合适分布键

分布键选择不当会导致重分布、数据分布不均等,而数据分布不均会使SQL集中在一个segment节点的执行,限制了gp整体的速度。

  • 使所有节点数据存放是均匀的,数据分布均匀才能充分利用多台机器查询,发挥分布式的优势。
  • join、开窗函数等尽量以分布键作为关联键、分区键。尤其需要注意的是join、开窗函数会依据关联键、分区键做重分布或者广播操作,因而若分布键和关联键不一致,不论如何修改分布键,也是需要再次重分布的。
  • 尽量保证where条件产生的结果集的存储也尽量是均匀的。
  • 查看某表是否分布不均: select gp_segment_id,count(*) from fact_tablegroup by gp_segment_id
  • 在segment一级,可以通过select gp_segment_id,count(*) from fact_table group by gp_segment_id的方式检查每张表的数据是否均匀存放
  • 在系统级,可以直接用df -h 或du -h检查磁盘或者目录数据是否均匀
  • 查看数据库中数据倾斜的表

    首先定义数据倾斜率为:最大子节点数据量/平均节点数据量。为避免整张表的数据量为空,同时对结果的影响很小,在平均节点数据量基础上加上一个很小的值,SQL如下:

1. SELECT tabname,
2. max(SIZE)/(avg(SIZE)+0.001) AS max_div_avg,
3. sum(SIZE) total_size
4. FROM
5. (SELECT gp_segment_id,
6. oid::regclass tabname,
7. pg_relation_size(oid) SIZE
8. FROM gp_dist_random(‘pg_class‘)
9. WHERE relkind=‘r‘
10. AND relstorage IN (‘a‘,‘h‘)) t
11. GROUP BY tabname
12. ORDER BY 2 DESC;

分区表

按照某字段进行分区,不影响数据在数据节点上的分布,但是,仅在单个数据节点上,对数据进行分区存储。可以加快分区字段的查询速度。

压缩表

对于大AO表和分区表使用压缩,以节省存储空间并提高系统I/O,也可以在字段级别配置压缩。应用场景:

  • 不需要对表进行更新和删除操作
  • 访问表的时候基本上是全表扫描,不需要建立索引
  • 不能经常对表添加字段或者修改字段类型

分组扩展

Greenplum数据库的GROUP BY扩展可以执行某些常用的计算,且比应用程序或者存储过程效率高。

    GROUP BY ROLLUP(col1, col2, col3)
    GROUP BY CUBE(col1, col2, col3)
    GROUP BY GROUPING SETS((col1, col2), (col1, col3))

ROLLUP 对分组字段(或者表达式)从最详细级别到最顶级别计算聚合计数。ROLLUP的参数是一个有序分组字段列表,它计算从右向左各个级别的聚合。例如 ROLLUP(c1, c2, c3) 会为下列分组条件计算聚集:

    (c1, c2, c3)
    (c1, c2)
    (c1)
    ()

CUBE 为分组字段的所有组合计算聚合。例如 CUBE(c1, c2, c3) 会计算一下聚合:

    (c1, c2, c3)
    (c1, c2)
    (c2, c3)
    (c1, c3)
    (c1)
    (c2)
    (c3)
    ()

GROUPING SETS 指定对那些字段计算聚合,它可以比ROLLUP和CUBE更精确地控制分区条件。

窗口函数

窗口函数可以实现在结果集的分组子集上的聚合或者排名函数,例如 sum(population) over (partition by city)。窗口函数功能强大,性能优异。因为它在数据库内部进行计算,避免了数据传输。

  • 窗口函数row_number()计算一行在分组子集中的行号,例如 row_number() over (order by id)。
  • 如果查询计划显示某个表被扫描多次,那么通过窗口函数可能可以降低扫描次数。
  • 窗口函数通常可以避免使用自关联。

列存储和行存储

列存储亦即同一列的数据都连续保存在一个物理文件中,有更高的压缩率,适合在款表中对部分字段进行筛选的场景。

需要注意的是:若集群中节点较多,而且表的列也较多,每个节点的每一列将会至少产生一个文件,那么总体上将会产生比较多的文件,对表的DDL操作就会比较慢。在和分区表使用时,将会产生更多文件,甚至可能超过linux的文件句柄限制,要尤其注意。

  • 行存储:如果记录需要update/delete,那么只能选择非压缩的行存方式。对于查询,如果选择的列的数量经常超过30个以上的列,那么也应该选择行存方式。
  • 列存储:如果选择列的数量非常有限,并且希望通过较高的压缩比换取海量数据查询时的较好的IO性能,那么就应该选择列存模式。其中,列存分区表,每个分区的每个列都会有一个对应的物理文件,所以要注意避免文件过多,导致可能超越linux上允许同时打开文件数量的上限以及DDL命令的效率很差。

函数和存储过程

虽然支持游标但是,尽量不要使用游标方式处理数据,而是应该把数据作为一个整体进行操作。

索引使用

  • 如果是从超大结果集合中返回非常小的结果集(不超过5%),建议使用BTREE索引(非典型数据仓库操作)
  • 表记录的存储顺序最好与索引一致,可以进一步减少IO(好的index cluster)
  • where条件中的列用or的方式进行join,可以考虑使用索引
  • 键值大量重复时,比较适合使用bitmap索引

有关索引使用的测试见GP索引调优测试–基本篇GP索引调优测试–排序篇

NOT IN

  • 在gp4.3中已经进行了优化,采用hash left anti semi join进行连接。
  • 以下只针对gp4.1及之前
    • 有not in的SQL,都会采用笛卡尔积来执行,采用nested join,效率极差
    • not in==》改用left join去重后的表关联来实现
    • 例子
       select * from test1 where col1 not in (select col2 from test1)
      

      改为

       select * from test1 a left join (select col2 from test1 group bycol2) b on a.col1=b.col2 where b.col2 is null
      

      运行时间由30多秒提升至92毫秒。

聚合函数太多

  • 一条SQL中聚合函数太多,而且可能由于统计信息不够详细或者SQL太负责,错选hashaggregate来执行,导致内存不足。
  • 解决方法:
    • 拆分成多个SQL来执行,减少hashaggregate使用的内存
    • 执行enable_hashagg=off,把hashaggregate参数关掉,强制不采用。将会采用groupaggregate,这样排序时间会长一些,但是内存可控,建议采用这种方式比较简单。

资源队列

数据写入、查询分别使用不同的用户,GP创建用户时为不同用户指定不同的资源队列。

其它优化技巧

  • 用group by对distinct改写,因为DISTINCT要进行排序操作
  • 用UNION ALL加GROUP BY的方式对UNION改写
  • 尽量使用GREENPLUM自身提供的聚合函数和窗口函数去完成一些复杂的分析

参考

时间: 2024-11-03 21:42:17

Greenplum优化--SQL调优篇的相关文章

Android性能调优篇之UI布局优化

详细内容请查看我的简书地址:Android性能调优篇之UI布局优化 或者我的个人博客地址:Android性能调优篇之UI布局优化

PLSQL_硬解析和解析的区别(案例)(进行SQL优化性能调优的基础,了解解析过程)

2014-08-11 BaoXinjian 一.摘要 Oracle硬解析和软解析是我们经常遇到的问题,所以需要考虑何时产生软解析何时产生硬解析,如何判断 SQL的执行过程 当发布一条SQL或PL/SQL命令时,Oracle会自动寻找该命令是否存在于共享池中来决定对当前的语句使用硬解析或软解析. 通常情况下,SQL语句的执行过程如下: Step1. SQL代码的语法(语法的正确性)及语义检查(对象的存在性与权限). Step2. 将SQL代码的文本进行哈希得到哈希值. Step3. 如果共享池中存

《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)

继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(index).我们知道,<高性能SQL调优精要与案例解析>一书中也再三强调索引对SQL调优的重要性,可是上篇文章中也谈到,只看案例和解决问题的具体方法,而不掌握SQL调优的基础知识,是没有用的,我们必须做到知其然,更要知其所以然,才能做到融会贯通,活学活用,进而将SQL调优技术掌握到炉火纯青的地步.

Oracle SQL 调优健康检查脚本

Oracle SQL 调优健康检查脚本 我们关注数据库系统的性能,进行数据库调优的主要工作就是进行SQL的优化.良好的数据架构设计.配合应用系统中间件和写一手漂亮的SQL,是未来系统上线后不出现致命性能问题的有力保证. 在CBO时代,一个SQL的执行计划是多样的.影响执行计划的因素也从过去RBO时代的SQL书写规则变为综合性因素.这为我们生成更加优秀执行计划提供了基础,同时也给我们进行调优带来的很多麻烦. 目前我们通常的做法,是通过AWR报告或者调试手段,发现某某SQL有问题,之后从Librar

MySQL 数据库规范--调优篇(终结篇)

前言 这篇是MySQL 数据库规范的最后一篇--调优篇,旨在提供我们发现系统性能变弱.MySQL系统参数调优,SQL脚本出现问题的精准定位与调优方法. 目录 1.MySQL 调优金字塔理论 2.MySQL 慢查询分析--mysqldumpslow.pt_query_digest工具的使用(SQL脚本层面) 3.选择合适的数据类型 4.去除无用的索引--pt_duplicate_key_checker工具的使用(索引层面) 5.反范式化设计(表结构) 6.垂直水平分表 7.MySQL 重要参数调优

Oracle SQL调优记录

目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太多表.面对复杂的业务场景,确实有些情况是需要关联很多表的.当然有些情况是可以将业务实现放在Java代码里,有些情况可以不要关联很多表. 二.注意点 对于SQL调优,不要马上就说加索引什么的,加索引不一定就能解决问题的,加错索引,反而会导致查询变慢,注意加索引的同时也会影响数据库写数据的速度. 三.O

SQL调优日志--内存问题

SQL调优日志--内存问题排查入门篇 概述 很多系统的性能问题,是由内存导致的.内存不够会导致页面频繁换入换出,IO队列高,进而影响数据库整体性能. 排查 内存对数据库性能非常重要.那么我当出现问题的时候,我们怎么排查性能问题呢? 存在问题 主要查看2个部分.页生命周期 Page Life Expectancy,和  lazy writer /sec. 页生命周期 的参考值在很久很久以前,很多同学可能看到过,建议值是300s.但是这是基于32位操作系统,最大只能使用4GB内存给出的. Jonat

SQL调优

# 问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一.系统优化中一个很重要的方面就是SQL语句的优 化.对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的 SQL语句,提高系统的可用性. 在多数情况下,Oracle

SQL调优常用方法

在使用DBMS时经常对系统的性能有非常高的要求:不能占用过多的系统内存和 CPU资源.要尽可能快的完成的数据库操作.要有尽可能高的系统吞吐量.如果系统开发出来不能满足要求的所有性能指标,则必须对系统进行调整,这个工作被称为调优.绝定DBMS的性能的因素有两个因素:硬件和软件.使用频率高的CPU.使用多处理器.加大内存容量.增加Cache.提高网络速度等这些都是非常有效的硬件调优方式,不过对硬件进行调优对系统性能的提高是有限的,如果有非常好的硬件条件但是如果编写的SQL质量非常差的话系统的性能并不