摘要:我们还能继续优化,使用的语句进行子查询。解决方法不要用解决方法用注释在查询语句前添加注释,能让查询更快些。但是,如果使用了语句,这个魔术注释将被忽略。
查询速度慢, 如何优化? 解决方法1: 避免单节点处理
虽然Presto是分布式查询引擎, 但是一些操作是必须在单节点中处理的. 例如:
count(distinct x)
考虑使用approx_distinct(x)代替
但是需要注意这个函数有个大约在2.3%的标准误差, 如果需要精确统计的情况, 请绕道.
UNION
UNION有个功能是: 如果两条记录一样, 会只保留一条记录(去重).
如果不考虑去重的情况, 请使用UNION ALL
ORDER BY
Presto对数据排序是作用在单节点上的
如果要排序的数据量超过百万行, 要谨慎考虑. 如果非要排序,尽量将排序的字段减少些.
解决方法2: 减少表扫描的范围通过添加条件达到减少表扫描的范围.
也可以考虑将大数据量的表, 水平查分, 通过查不同的表分区达到效果.
解决方法3: 避免使用 SELECT * FROM要明确写出所有要访问的列, 能加快速度.
例如
SELECT * FROM my_table
改成:
SELECT id, name, address FROM my_table解决方法4: 将几个LIKE语句放到函数regexp_like()
Presto的查询优化器不能改善许多LIKE语句使用的地方, 导致这样的语句查询速度慢.
例如
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性能?
尽量让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如何使查询简单化 解决方法1: 使用WITH语句
如果你的查询语句非常复杂或者有多层嵌套的子查询,请试着用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解决方法2:在CREATE TABLE语句中使用WITH语句
如果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解决方法3:用GROUP BY语句时,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")
上面的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开始。Exceeded max (local) memory 错误
Presto会跟踪每个查询的内存使用情况.可用内存的多少是根据你的查询计划变动的,所以在大多数情况下可以从写查询语句来达到优化内存使用的目的.
下面列出来的就是内存密集型的语句块:
district
UNION
ORDER BY
GROUP BY (许多字段的情况)
joins (各种JOIN)
解决方法1: 尽量少使用distinctdistinct 会排除所有不唯一的行.下面的例子就是检查你的数据表中是否包含了相同的数据行(c1,c2,c3)
SELECT distinct c1, c2, c3 FROM my_table
上面的操作会存储一整字段c1,c2和c3到presto的单个工作节点的内存, 然后检查(c1,c2,c3)的唯一性. 随着字段的增多以及字段数据量的增大,所需要的内存也会直线上升.
所以, 去掉查询语句中的distinct关键字, 或者只在子查询(有有限少量字段的情况下)使用.
解决方法2: 用approx_distinct(x)代替count(distinct x)NOTE: approx_distinct(x)会返回一个正确的近似值, 如果只是需要看一个大概的趋势,可以考虑.解决方法3: 尽量用UNION ALL代替UNION
和distinct的原因类似, UNION有去重的功能, 所以会引发内存使用的问题.解决方法4: 尽量避免ORDER BY如果你只是拼接两个或者多个SQL查询的结果, 考虑用UNION ALL
SELECT c1, c2 FROM my_table ORDER BY c1
Presto在排序的时候启用的是单一节点进行工作, 所以整个数据需要在单节点内存限制的范围内, 超过这个内存限制就会报错.
如果你需要排序的数据在一个小的量级, 用ORDER BY没有问题; 如果需要排序的数据在GB的级别,需要考虑其他的解决方案.
例如: 大量级的数据排序可以考虑结合HIVE和presto. 首先, 用Presto将大量的数据存储到一个临时表中,然后用HIVE取对数据排序.
解决方法5: 减少GROUP BY的字段SELECT avg(c1), min_by(c2, time), max(c3), count(c4), ... FROM my_table GROUP BY c1, c2, c3, c4, ...
减少GROUP BY语句后面的排序一句字段的数量能减少内存的使用.
解决方法6:用大表取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的效率慢.
Presto用JOSN text的形式保存数据。如果查询出来的数据大于100G,Presto将传输大于100G的JSON text来保存查询结果。所以,即使查询处理即将完成,输出这么大的JOSN text也会消耗很长时间。解决方法1:不要用==SELECT *== 解决方法2:用result_output_redirect="true" 注释
在查询语句前添加注释(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"如何在字段包含NULL的情况下 添加default value 解决方法:用COALESCE(v1,v2,...)函数
-- This retuns "N/A" if name value is null SELECT COALESCE(name, "N/A") FROM table1如何从两个数中选出最大/最小值 解决方法:用greatest / least 函数
SELECT greatest(5, 10) -- returns 10Binary函数的应用
这里主要的问题是:如何将binary/varbinary类型转换为varchar类型转换SHA256/MD5
SELECT to_hex(sha256(to_utf8("support@treasure-data.com"))) as email SELECT to_hex(md5(to_utf8("support@treasure-data.com"))) as email转换base64
SELECT to_base64(to_utf8("support@treasure-data.com")) as email => "c3VwcG9ydEB0cmVhc3VyZS1kYXRhLmNvbQ==" SELECT FROM_UTF8(from_base64("c3VwcG9ydEB0cmVhc3VyZS1kYXRhLmNvbQ==")) => "support@treasure-data.com"
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/32222.html
摘要:经过一段时间的工作,有了些感觉,决定将遇到的一些坑记录下来。利用子查询,减少读表的次数,尤其是大数据量的表具体做法是,将使用频繁的表作为一个子查询抽离出来,避免多次。 最近换了新工作,在数据处理方面,公司是用Presto连接各个业务部的数据库,直接上SQL处理数据。一度是不是很适应。经过一段时间的工作,有了些感觉,决定将遇到的一些坑记录下来。 Presto的是什么?优势是什么呢?从官方...
摘要:经过一段时间的工作,有了些感觉,决定将遇到的一些坑记录下来。利用子查询,减少读表的次数,尤其是大数据量的表具体做法是,将使用频繁的表作为一个子查询抽离出来,避免多次。 最近换了新工作,在数据处理方面,公司是用Presto连接各个业务部的数据库,直接上SQL处理数据。一度是不是很适应。经过一段时间的工作,有了些感觉,决定将遇到的一些坑记录下来。 Presto的是什么?优势是什么呢?从官方...
摘要:跟踪每个的活动情况并协调查询语句的执行。是负责执行任务和处理数据。是负责从获取结果并返回最终结果给。例如,一个表的权限定名是,则是表名,是,是。运行启动命令日志在目录下记录服务初始化情况和一些的诊断。 Presto简介 不是什么 虽然Presto可以解析SQL,但它不是一个标准的数据库。不是MySQL、PostgreSQL或者Oracle的代替品,也不能用来处理在线事务(OLTP) 是...
摘要:存储层一般是,但也有可以查询,或者关系数据库的。在关系数据库中早有另一种优化方式,也就是基于代价的优化。这些都已经在关系数据库中得到了实践。 考虑到系统使用的广泛程度与成熟度,在具体举例时一般会拿Hive和Impala为例,当然在调研的过程中也会涉及到一些其他系统,如Spark SQL,Presto,TAJO等。而对于HAWQ这样的商业产品和apache drill这样成熟度还不是很高的开源...
摘要:下文总结了一些这个领域的开源项目,供参考。支持初期由开发,现在也是积极用户和贡献者基于的关系型数据库层。支持由开发基于的数据查询执行引擎。支持由和开源社区开发严格意义上不属于,但是其有特殊的技术,所以值得一提。 随着Hadoop的流行,越来越多的企业把数据存储在Hadoop上,或者Non-SQL数据库上,随之相关的数据处理技术也从一开始的Map Reduce一统江湖,到现在各种技术竞相...
阅读 702·2023-04-25 23:40
阅读 3538·2021-11-22 15:22
阅读 3307·2021-10-09 09:44
阅读 3258·2021-09-23 11:52
阅读 1055·2021-09-22 15:43
阅读 656·2021-09-10 10:51
阅读 2079·2021-09-06 15:02
阅读 3010·2021-09-06 15:02