雖然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"