虽然Presto是分布式查询引擎, 可是一些操做是必须在单节点中处理的. 例如:sql
count(distinct x)网络
UNIONsession
UNION有个功能是: 若是两条记录同样, 会只保留一条记录(去重).
ORDER BYapp
Presto对数据排序是做用在单节点上的
经过添加条件达到减小表扫描的范围.分布式
也能够考虑将大数据量的表, 水平查分, 经过查不一样的表分区达到效果.函数
要明确写出全部要访问的列, 能加快速度.
例如性能
SELECT * FROM my_table
改为:大数据
SELECT id, name, address FROM my_table
Presto的查询优化器不能改善许多LIKE语句使用的地方, 致使这样的语句查询速度慢.优化
例如ui
SELECT ... FROM access WHERE method LIKE '%GET%' OR method LIKE '%POST%' OR method LIKE '%PUT%' OR method LIKE '%DELETE%'
上面的语句能用regexp_like函数优化成一句
SELECT ... FROM access WHERE regexp_like(method, 'GET|POST|PUT|DELETE')
尽可能让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)
上面的SQL语句的JOIN性能不高,由于JION条件包含了表达式计算。咱们能够经过子查询的形式来优化上面的语句。
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
上面的语句,就是直接比较两个VARCHAR的值,这样会比比较一个VARCHAR和一个表达式结果的性能高。
咱们还能继续优化,使用Presto的WITH语句进行子查询。
WITH b AS ( SELECT CAST((b.year * 10000 + b.month * 100 + b.day) as VARCHAR) date, # generate join key name FROM right_table ) SELECT a.date, b.name FROM left_table a JOIN b ON a.date = b.date
若是你的查询语句很是复杂或者有多层嵌套的子查询,请试着用WITH语句将子查询分离出来。
例如
SELECT a, b, c FROM ( SELECT a, MAX(b) AS b, MIN(c) AS c FROM tbl GROUP BY a ) tbl_alias
能够被重写为线面的形式
WITH tbl_alias AS (SELECT a, MAX(b) AS b, MIN(c) AS c FROM tbl GROUP BY a) SELECT a, b, c FROM tbl_alias
一样,也能够将各个步骤的子查询经过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
在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')
上面的SQL语句的GROUP BY部分能够用GROUP BY 1,2,3 ...来表示
SELECT TD_TIME_FORMAT(time, 'yyyy-MM-dd HH', 'PDT') hour, count(*) cnt FROM my_table GROUP BY 1
Note: 这些数字是从1开始的,有别于程序要思惟从0开始。
Presto会跟踪每一个查询的内存使用状况.可用内存的多少是根据你的查询计划变更的,因此在大多数状况下能够从写查询语句来达到优化内存使用的目的.
下面列出来的就是内存密集型的语句块:
distinct 会排除全部不惟一的行.下面的例子就是检查你的数据表中是否包含了相同的数据行(c1,c2,c3)
SELECT distinct c1, c2, c3 FROM my_table
上面的操做会存储一整字段c1,c2和c3到presto的单个工做节点的内存, 而后检查(c1,c2,c3)的惟一性. 随着字段的增多以及字段数据量的增大,所须要的内存也会直线上升.
因此, 去掉查询语句中的distinct关键字, 或者只在子查询(有有限少许字段的状况下)使用.
NOTE: approx_distinct(x)会返回一个正确的近似值, 若是只是须要看一个大概的趋势,能够考虑.
和distinct的缘由相似, UNION有去重的功能, 因此会引起内存使用的问题.若是你只是拼接两个或者多个SQL查询的结果, 考虑用UNION ALL
SELECT c1, c2 FROM my_table ORDER BY c1
Presto在排序的时候启用的是单一节点进行工做, 因此整个数据须要在单节点内存限制的范围内, 超过这个内存限制就会报错.
若是你须要排序的数据在一个小的量级, 用ORDER BY没有问题; 若是须要排序的数据在GB的级别,须要考虑其余的解决方案.
例如: 大量级的数据排序能够考虑结合HIVE和presto. 首先, 用Presto将大量的数据存储到一个临时表中,而后用HIVE取对数据排序.
SELECT avg(c1), min_by(c2, time), max(c3), count(c4), ... FROM my_table GROUP BY c1, c2, c3, c4, ...
减小GROUP BY语句后面的排序一句字段的数量能减小内存的使用.
下面这种用小数据表去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
若是左表和右表都比较大怎么办?
-- 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的效率慢.
Presto用JOSN text的形式保存数据。若是查询出来的数据大于100G,Presto将传输大于100G的JSON text来保存查询结果。因此,即便查询处理即将完成,输出这么大的JOSN text也会消耗很长时间。
在查询语句前添加注释(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'
-- This retuns 'N/A' if name value is null SELECT COALESCE(name, 'N/A') FROM table1
SELECT greatest(5, 10) -- returns 10
这里主要的问题是:如何将binary/varbinary类型转换为varchar类型
SELECT to_hex(sha256(to_utf8('support@treasure-data.com'))) as email SELECT to_hex(md5(to_utf8('support@treasure-data.com'))) as email
SELECT to_base64(to_utf8('support@treasure-data.com')) as email => "c3VwcG9ydEB0cmVhc3VyZS1kYXRhLmNvbQ==" SELECT FROM_UTF8(from_base64('c3VwcG9ydEB0cmVhc3VyZS1kYXRhLmNvbQ==')) => "support@treasure-data.com"