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对数据排序是作用在单节点上的,如果排序超过百万行,要慎重考虑。如果非要排序,尽量将排序的字段减少些。
- 如果需要多个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')
- 优化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
- 使用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
- 在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
- 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开始的。
- 用大表取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语句,这个魔术注释将被忽略。
- 字符串拼接
select ‘hello’ || ‘presto’