presto常见问题总结:

1.提升性能优化方法

  • Exceeded max (local) memory 错误
    Presto会跟踪每个查询的内存使用情况.可用内存的多少是根据你的查询计划变动的,所以在大多数情况下可以从写查询语句来达到优化内存使用的目的.
    下面列出来的就是内存密集型的语句块:
    district
    UNION
    ORDER BY
    GROUP BY (许多字段的情况)
    joins (各种JOIN)

解决方法:

  • count(distinct x)
    可以用approx_distinct(x)代替,但是这个函数有大约2.3的标准误差,如果不需要精确统计,可考虑使用。
  • UNION
    如果两条记录一样,会只保留一条记录(去重)
    如果不去重,请使用UNION ALL
  • order by
    presto对数据排序是作用在单节点上的,如果排序超过百万行,要慎重考虑。如果非要排序,尽量将排序的字段减少些。
  1. 如果需要多个like语句可以用regexp_like()
    例如:
select ...
from table
where
	col like '%aa%' or
	col like '%bb%' or
	col like '%cc%' or

👇

select ...
from table
where
	regexp_like(col,'aa|bb|cc')
  1. 优化JOIN性能
    尽量让join的条件简单,on后面的比较表达式两边不涉及计算。
    例如
SELECT a.date, b.name FROM
left_table a
JOIN right_table b
ON a.date = CAST((b.year * 10000 + b.month * 100 + b.day) as VARCHAR)

👇

SELECT a.date, b.name FROM
left_table a
JOIN (
  SELECT
    CAST((b.year * 10000 + b.month * 100 + b.day) as VARCHAR) date,  # generate join key
    name
  FROM right_table
) b
ON a.date = b.date  # Simple equi-join
  1. 使用with语句
WITH tbl1 AS (SELECT a, MAX(b) AS b, MIN(c) AS c FROM tbl GROUP BY a),
     tbl2 AS (SELECT a, AVG(d) AS d FROM another_tbl GROUP BY a)
SELECT tbl1.*, tbl2.* FROM tbl1 JOIN tbl2 ON tbl1.a = tbl2.a
  1. 在create table语句中使用with语句
    例如:
CREATE TABLE tbl_new AS WITH tbl_alias AS (SELECT a, MAX(b) AS b, MIN(c) AS c FROM tbl1)
SELECT a, b, c FROM tbl_alias

👇

CREATE TABLE tbl_new AS WITH tbl_alias1 AS (SELECT a, MAX(b) AS b, MIN(c) AS c FROM tbl1),
                             tbl_alias2 AS (SELECT a, AVG(d) AS d FROM tbl2)
SELECT tbl_alias1.*, tbl2_alias.* FROM tbl_alias1 JOIN tbl_alias2 ON tbl_alias1.a = tbl_alias2.a
  1. group by的目标可用数字代替
    在Presto SQL中,GROUP BY语句需要与SELECT语句中的表达式保持一致,不然会提示语法错误。
    例如:
SELECT TD_TIME_FORMAT(time, 'yyyy-MM-dd HH', 'PDT') hour, count(*) cnt
FROM my_table
GROUP BY TD_TIME_FORMAT(time, 'yyyy-MM-dd HH', 'PDT')

👇

SELECT TD_TIME_FORMAT(time, 'yyyy-MM-dd HH', 'PDT') hour, count(*) cnt
FROM my_table
GROUP BY 1

ps:presto的索引是从1开始的。

  1. 用大表取JOIN小表
    下面这种用小数据表去JOIN大数据表的查询会极度消耗内存。
SELECT * FROM small_table, large_table
WHERE small_table.id = large_table.id

Presto 会默认执行广播式的JOIN操作,它会将左表拆分到几个工作节点上, 然后发送整个右表分别到已拆分好的处理左表的工作节点上. 如果右表非常大就会超出工作节点的内存限制,进而出错.
所以需要用大表JOIN小表

SELECT * FROM large_table, small_table
WHERE large_table.id = small_table.id

如果左表和右表都比较大怎么办?

修改配置distributed-joins-enabled (presto version >=0.196)
在每次查询开始使用distributed_join的session选项

-- set session distributed_join = 'true'
SELECT * FROM large_table, large_table1
WHERE large_table1.id = large_table.id

核心点就是使用distributed join. Presto的这种配置类型会将左表和右表同时以join key的hash value为分区字段进行分区. 所以即使右表也是大表,也会被拆分.
缺点是会增加很多网络数据传输, 所以会比broadcast join的效率慢.
8. 在查询语句前添加注释(result_output_redirect=‘true’),能让查询更快些。

-- set session result_output_redirect='true'
select a, b, c, d FROM my_table

上面的语句能让Presto用并行的方式生成查询结果,能跳过在Presto协调器进行JSON转换的过程。

Note: 但是,如果使用了ORDER BY语句,这个魔术注释将被忽略。

  1. 字符串拼接
select ‘hello’ || ‘presto’