2018年10月2日
- 本番環境のPresto 0.205 アップグレードに向けた準備
- サイドバイサイド環境
- 移行タイムライン
- Presto 0.205とPresto 0.188でのコード実行
- Presto 0.205に必要なSQL変更
- 新しいシステム関数 current_user
- 構文エラーを発生させるクエリ
- ORDER BY動作の変更
- USINGを使用したJOIN
- エラーメッセージ: Given correlated subquery is not supported
- 推奨される更新: TD_SESSIONIZEをTD_SESSIONIZE_WINDOWに置き換える
Treasure Dataの新しいPrestoリリース(2018年10月1日提供開始)は、オープンソースのPresto 0.205リリースをベースにしています。以前のリリースはPresto 0.188をベースにしていました。
互換性とパフォーマンス低下の問題を特定するため、独自の内部テストを実施しており、その内容を以下に記載しています。
お客様も独自にテストを行う必要があることを理解しています。そのため、今回のリリースではPresto 0.188とPresto 0.205をサイドバイサイドで提供し、お客様がアップグレード前に自身でコードをテストできるようにしています。
2018年10月31日までは、デフォルト環境はPresto 0.188となります。2018年11月1日に、デフォルト環境はPresto 0.205に切り替わります。Presto 0.188は2018年11月15日まで利用可能で、移行を完了する時間を確保しています。
10月31日より前に互換性テストを完了した場合は、Treasure Dataサポートにご連絡いただければ、お客様のデフォルトを早期にPresto 0.205に変更することができます。
サイドバイサイド環境と段階的な移行期間は、今後のリリースでも継続して実施されます。
Presto 0.188からPresto 0.205への移行期間中、2つのリリースは2018年10月1日から2018年11月15日までサイドバイサイドで利用可能です。
以下のクエリヒントを使用して、どのPrestoリリースでコードを実行するかを制御できます:
-- @TD engine_version: 0.188または
-- @TD engine_version: 0.205今回のリリースでは、主にANSI SQL標準への準拠を強化することに焦点を当てた、多数のPresto構文変更があります。
既存のクエリの一部は、新しいPresto環境で実行する前に修正が必要になります。以下で説明する変更については、クエリはPresto 0.188とも互換性があることに注意してください。したがって、**結果を変更することなく、Presto 0.188環境でこれらの変更を行うことができます。**新しいリリースに移行しても、クエリは引き続き動作します。
ここに記載されている必須の変更は、既存のお客様のコードを実行することで特定されました。
各変更について、Prestoでの変更内容、互換性のないPresto SQLがある場合のエラーメッセージ、および推奨される書き換え方法を説明します。
Prestoに新しいcurrent_user()関数が追加されました。この関数は現在のユーザー名を返します。その結果、current_user()という名前のカラムやエイリアスがある場合は、そのカラムへの参照を引用符で囲む必要があります。
例えば、変更前にこのコードがある場合:
SELECT current_user FROM table1"current_user"を引用符で囲むように更新します:
SELECT "current_user" FROM table1
-- tab."current_user"カラムの値をリストしますPrestoはANSI SQL標準のORDER BY句により厳密に準拠するようになりました。
ORDER BY動作の一般的なルールは次のようになります:
ORDER BYは射影(projection)の後に実行されます
ORDER BYは可能な限り序数エイリアスを優先します
入力カラムと出力カラムはORDER BY句で使用できますが、曖昧さがある場合は出力カラムがより高い優先順位を持ちます
このPrestoの変更により、いくつかのエラーメッセージが発生する可能性があります。
以下のすべてのケースの問題は、クエリ内の命名の競合によるものです。つまり、SELECTまたはORDER BYでのエイリアスの使用が、入力のカラム名またはテーブル名と衝突しています。エイリアスを使用すると、元の入力テーブルまたはカラムへの参照ができなくなります。
書き換えは一般的に、入力テーブルまたはカラム名と一致しないエイリアスを使用するか、ORDER BY句で序数を使用することを含みます。
各ケースについて、メッセージ、エラーを引き起こすクエリ、およびクエリを書き換える方法の例を示します。
エラーを引き起こす元のコード:
SELECT *
FROM page_view
WHERE CAST(week_page_total_actions as VARCHAR) IS DISTINCT FROM '0';エラーを修正する修正コード:
```sql
SELECT *
FROM page_view
WHERE CAST(week_page_total_actions as VARCHAR (1)) IS DISTINCT FROM '0';
### エラーメッセージ: Non deterministic ORDER BY expression is not supported with SELECT DISTINCT
エラーの原因となる元のコード:
```sql
SELECT
week_page_total_actions
FROM (
SELECT
DISTINCT week_page_total_actions,
rand()
FROM
page_view
WHERE
week_page_total_actions NOT LIKE '1'
ORDER BY
rand() LIMIT 20
) subエラーを修正したコード:
SELECT
week_page_total_actions
FROM (
SELECT
DISTINCT week_page_total_actions,
rand()
FROM
page_view
WHERE
week_page_total_actions NOT LIKE '1'
LIMIT 20
) sub
-- ORDER BY 句から関数または式を削除する
### エラーメッセージ: Invalid reference to output projection attribute from ORDER BY aggregation
エラーの原因となる元のコード:
```sql
SELECT
code, count(code) AS cnt
FROM www_access GROUP BY code ORDER BY count(code)
-- 出力カラムの code が ORDER BY 集約で使用されているエラーを修正したコード:
SELECT
code, count(code) AS cnt
FROM www_access GROUP BY code ORDER BY count(www_access.code)
-- (または) ORDER BY cnt (または) ORDER BY 2
### エラーメッセージ: Expression XXX is not of type ROW
エラーの原因となるコード例:
```sql
SELECT
TD_TIME_FORMAT(time,
'yyyy-MM-dd HH:mm:ss z',
'JST') AS time,
code AS access -- 優先度が高い
FROM www_access access -- 優先度が低い
ORDER BY access.time
-- access はここではエイリアスカラム "code" を参照する
-- そのため access.time は意味をなさないエラーを修正したコード:
SELECT
TD_TIME_FORMAT(time,
'yyyy-MM-dd HH:mm:ss z',
'JST') AS time,
code AS access_another -- 名前の競合を回避する
FROM www_access access
ORDER BY access.time次のクエリ(識別子 time で名前の衝突が発生する場合)は、上記の書き換えと同等ではないことに注意してください。time としてエイリアスされたTD_TIME_FORMATの戻り値は、タイムスタンプではなく日付フォーマットされたVARCHARになります:
SELECT
TD_TIME_FORMAT(time,
'yyyy-MM-dd HH:mm:ss z',
'JST') AS time, -- エイリアスの優先度が高く、ORDER BY で使用される
count(*) AS access
FROM access_log access
ORDER BY time -- (または) ORDER BY 1エラーの原因となるコード例:
SELECT
DISTINCT TD_TIME_FORMAT(time,
'yyyy-MM-dd HH:mm:ss z',
'JST') AS time,
code
FROM www_access access
ORDER BY TD_TIME_FORMAT(time, 'yyyy-MM-dd HH:mm:ss z', 'JST')
-- このTD_TIME_FORMATの呼び出しはSELECTリストの式と一致しません。
-- ORDER BY内のtimeは、TD_TIME_FORMATによって返されたvarcharを参照しているためですエラーを修正した修正コード:
SELECT
DISTINCT TD_TIME_FORMAT(time,
'yyyy-MM-dd HH:mm:ss z',
'JST') AS time, -- より高い優先順位、入力時刻カラムをオーバーライドします
code
FROM www_access access
ORDER BY time
-- ORDER BY 1 を使用することもできます関数名は異なりますが、解決策は同じです。
関数 td_time_format に予期しないパラメータ (varchar, varchar(21), varchar(3)) があります。期待される形式: td_time_format(bigint, varchar, varchar) , td_time_format(bigint, varchar)
関数 date_trunc に予期しないパラメータ (varchar(5), varchar) があります。期待される形式: date_trunc(varchar(x), date) , date_trunc(varchar(x), time) , date_trunc(varchar(x), time with time zone) , date_trunc(varchar(x), timestamp) , date_trunc(varchar(x), timestamp with time zone)
エラーを引き起こす td_time_format のコード例:
SELECT
TD_TIME_FORMAT(time, 'yyyy-MM-dd HH:mm:ss z', 'JST') AS time, -- より高い優先順位、入力時刻カラムをオーバーライドします
code
FROM www_access access
ORDER BY TD_TIME_FORMAT(time, 'yyyy-MM-dd HH:mm:ss z', 'JST')-- ここのtimeはSELECTリストのvarchar出力カラムであり、
-- タイムスタンプ入力カラムではありません
-- したがって、ここの式はSELECTリストの式と同じではありませんエラーを修正する td_time_format の修正コード:
SELECT
TD_TIME_FORMAT(time, 'yyyy-MM-dd HH:mm:ss z', 'JST') AS time, -- より高い優先順位
code
FROM www_access access
ORDER BY time -- (または) ORDER BY 1SELECT… JOIN... でUSING句を使用した等結合の場合、USING句で指定されたカラムは、結合内の各テーブルごとに1回ずつ表示されるのではなく、修飾されていない名前で出力に1回だけ表示されます。修飾名でソーステーブルのカラムを参照するとエラーになります。
以前のPrestoと比較して、この変更により次のエラーメッセージが発生する可能性があります。それぞれについて、クエリを書き直す方法の例を示します。
エラーを引き起こすコード例:
SELECT
lineitem.orderkey, lineitem.quantity,
orders.totalprice, orders.orderkey
FROM lineitem JOIN orders
USING (orderkey);lineitem.orderkey と orders.orderkey への参照に注意してください。
エラーを修正する修正コード:
SELECT
orderkey, lineitem.quantity, orders.totalprice
FROM lineitem JOIN orders
USING (orderkey);相関サブクエリとLIMIT
アップグレード後、相関サブクエリはLIMIT句の使用をサポートしなくなりました。
LIMIT句を必要としないように相関サブクエリを書き直してください。
エラーを引き起こすコード例:
SELECT * FROM region r, LATERAL (
SELECT * FROM nation n
WHERE n.regionkey = r.regionkey LIMIT 1
) -- これは失敗しますエラーを修正する修正コード:
SELECT * FROM region r, LATERAL (
SELECT * FROM nation n
WHERE n.regionkey = r.regionkey
)この問題については、変更によってコードの意味が変わらないことを確認するために、コードを注意深く確認する必要があります。
このアップデートのためにコードを確認する際に、TD_SESSIONIZEを使用している既存のクエリに対して重要なアップグレードを行うこともお勧めします。TD_SESSIONIZE() 関数は、パフォーマンスの問題と一貫性のない結果のため廃止されました。代替となるPrestoウィンドウ関数TD_SESSIONIZE_WINDOW()は2016年に追加されました。これはTD_SESSIONIZEの問題に対処しています。クエリを書き直すための詳細な手順はこちらにあります: