暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Presto介绍及常用查询优化方法总结(推荐收藏)

硬核林川 2021-08-26
1508
1、Presto简介
Presto是Facebook开源的MPP(Massive Parallel Processing)SQL引擎,其理念来源于一个叫Volcano的并行数据库,该数据库提出了一个并行执行SQL的模型,它被设计为用来专门进行高速、实时的数据分析。
Presto是一个SQL计算引擎,分离计算层和存储层,其不存储数据,通过Connector SPI实现对各种数据源(Storage)的访问。
1.1 架构
Presto沿用了通用的Master-Slave架构,一个Coordinator,多个Worker。
Coordinator负责解析SQL语句,生成执行计划,分发执行任务给Worker节点执行,Worker节点负责实际执行查询任务。
Presto提供了一套Connector接口,用于读取元信息和原始数据。
Presto 内置有多种数据源,如 Hive、MySQL、Kudu、Kafka 等。
Presto 的扩展机制允许自定义 Connector,从而实现对定制数据源的查询。
假如配置了Hive Connector,需要配置一个Hive MetaStore服务为Presto提供Hive元信息,Worker节点通过Hive Connector与HDFS交互,读取原始数据。
1.2 实现低延时的原理
Presto是一个交互式查询引擎,我们最关心的是Presto实现低延时查询的原理,以下几点是其性能脱颖而出的主要原因:
  • 完全基于内存的并行计算
  • 流水线
  • 本地化计算
  • 动态编译执行计划
  • 小心使用内存和数据结构
  • GC控制
  • 无容错
2、Presto查询优化
2.1 存储优化
① 合理设置分区
与Hive类似,Presto会根据元信息读取分区数据,合理的分区能减少Presto数据读取量,提升查询性能。
② 使用列式存储
Presto对ORC文件读取做了特定优化,因此在Hive中创建Presto使用的表时,建议采用ORC格式存储。相对于Parquet,Presto对ORC支持更好
③ 使用压缩
数据压缩可以减少节点间数据传输对IO带宽压力,对于即席查询需要快速解压,建议采用snappy压缩
④ 预先排序
有条件的话提前做好排序,对于已经排序的数据,在查询的数据过滤阶段,ORC格式支持跳过读取不必要的数据。
比如对于经常需要过滤的字段可以预先排序。
2.2 查询优化
① select时只选择必要字段,避免使用 * 号
② 过滤条件加上分区字段,减少查询数据量
③ 合理安排Group by语句中字段顺序对性能有一定提升
将Group By语句中字段按照每个字段distinct数据多少进行降序排列。示例中uid是用户id,比性别数据大很多。
    [GOOD]: SELECT GROUP BY uid, gender 
    [BAD]:  SELECT GROUP BY gender, uid
    ④ Order by时使用Limit
    Order by需要扫描数据到单个worker节点进行排序,导致单个worker需要大量内存。如果是查询Top N或者Bottom N,使用limit可减少排序计算和内存压力。
    ⑤ 用regexp_like代替多个like语句
    Presto查询优化器没有对多个like语句进行优化,使用regexp_like对性能有较大提升
      [GOOD] 
      SELECT ... 
      FROM access 
      WHERE regexp_like(method, 'GET|POST|PUT|DELETE')


      [BAD]
      SELECT ... 
      FROM access 
      WHERE 
      method LIKE '%GET%' OR  
      method LIKE '%POST%' OR  
      method LIKE '%PUT%' OR  
      method LIKE '%DELETE%'
      ⑥ 使用Rank函数代替row_number函数来获取Top N
      在进行一些分组排序场景时,使用rank函数性能更好
      2.3 Join优化
      ① 使用Join语句时将大表放在左边
      Presto中join的默认算法是broadcast join,即将join左边的表分割到多个worker,然后将join右边的表数据整个复制一份发送到每个worker进行计算。
      如果右边的表数据量太大,则可能会报内存溢出错误。
      ② 如果左表和右表都比较大
      为防止内存溢出,做如下配置:
      1)修改配置distributed-joins-enabled (presto version >=0.196)
      2)在每次查询开始使用distributed_join的session选项
        set session distributed_join = 'true' 


        SELECT ... 
        FROM
        large_table1
        join large_table2
        on large_table1.id = large_table2.id
        核心点就是使用distributed join,也就是hash join。
        Presto的这种配置类型会将左表和右表同时以join key的hash value为分区字段进行分区。
        所以即使右表也是大表,也会被拆分,相比broadcast join,这种join方式的会增加很多网络数据传输,效率慢。
        ③ 多个join的OR条件使用union代替
          SELECT ... 
          FROM 
          t1 
          JOIN t2
          ON t1.a1 = t2.a1 OR
          t1.a2 = t2.a2 


          改为


          SELECT ...
          FROM 
          t1 
          JOIN t2 
          ON t1.a1 = t2.a1
          union
          SELECT ...
          FROM 
          t1 
          JOIN t2
          ON t1.a2 = t2.a2
          ④ 使用WITH语句
          使用Presto分析统计数据时,可考虑把多次查询合并为一次查询,用Presto提供的子查询完成。
            WITH tmp AS ( 
            SELECT DISTINCT a1, a2
            FROM t2
            )
            SELECT ...
            FROM t1
            JOIN tmp
            ON t1.a1 = tmp.a1
            union
            SELECT ...
            FROM t1
            JOIN tmp
            ON t1.a2 = tmp.a2;
            ⑤ 尽量用UNION ALL代替UNION
            和distinct类似, UNION有去重的功能, 所以会使用到内存,如果只是拼接两个或者多个SQL查询的结果, 考虑用UNION ALL

            点击关注硬核林川,发送“全集资料”获取最新大数据资料
            文章转载自硬核林川,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论