Skip to content
Last updated

Presto 0.188から0.205への移行 2018

2018年10月2日

本番環境のPresto 0.205 アップグレードに向けた準備

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.205とPresto 0.188でのコード実行

Presto 0.188からPresto 0.205への移行期間中、2つのリリースは2018年10月1日から2018年11月15日までサイドバイサイドで利用可能です。

以下のクエリヒントを使用して、どのPrestoリリースでコードを実行するかを制御できます:

-- @TD engine_version: 0.188

または

-- @TD engine_version: 0.205

Presto 0.205に必要なSQL変更

今回のリリースでは、主にANSI SQL標準への準拠を強化することに焦点を当てた、多数のPresto構文変更があります。

既存のクエリの一部は、新しいPresto環境で実行する前に修正が必要になります。以下で説明する変更については、クエリはPresto 0.188とも互換性があることに注意してください。したがって、**結果を変更することなく、Presto 0.188環境でこれらの変更を行うことができます。**新しいリリースに移行しても、クエリは引き続き動作します。

ここに記載されている必須の変更は、既存のお客様のコードを実行することで特定されました。

各変更について、Prestoでの変更内容、互換性のないPresto SQLがある場合のエラーメッセージ、および推奨される書き換え方法を説明します。

新しいシステム関数 current_user

Prestoに新しいcurrent_user()関数が追加されました。この関数は現在のユーザー名を返します。その結果、current_user()という名前のカラムやエイリアスがある場合は、そのカラムへの参照を引用符で囲む必要があります。

例えば、変更前にこのコードがある場合:

SELECT current_user FROM table1

"current_user"を引用符で囲むように更新します:

SELECT "current_user" FROM table1
-- tab."current_user"カラムの値をリストします

構文エラーを発生させるクエリ

ORDER BY動作の変更

PrestoはANSI SQL標準のORDER BY句により厳密に準拠するようになりました。

ORDER BY動作の一般的なルールは次のようになります:

  • ORDER BYは射影(projection)の後に実行されます

  • ORDER BYは可能な限り序数エイリアスを優先します

  • 入力カラムと出力カラムはORDER BY句で使用できますが、曖昧さがある場合は出力カラムがより高い優先順位を持ちます

このPrestoの変更により、いくつかのエラーメッセージが発生する可能性があります。

以下のすべてのケースの問題は、クエリ内の命名の競合によるものです。つまり、SELECTまたはORDER BYでのエイリアスの使用が、入力のカラム名またはテーブル名と衝突しています。エイリアスを使用すると、元の入力テーブルまたはカラムへの参照ができなくなります。

書き換えは一般的に、入力テーブルまたはカラム名と一致しないエイリアスを使用するか、ORDER BY句で序数を使用することを含みます。

各ケースについて、メッセージ、エラーを引き起こすクエリ、およびクエリを書き換える方法の例を示します。

エラーメッセージ: Mismatched types: varchar(1) vs varchar

エラーを引き起こす元のコード:

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

エラーメッセージ: For SELECT DISTINCT, ORDER BY expressions must appear in select list

エラーの原因となるコード例:

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 1

USINGを使用したJOIN

SELECT… JOIN... でUSING句を使用した等結合の場合、USING句で指定されたカラムは、結合内の各テーブルごとに1回ずつ表示されるのではなく、修飾されていない名前で出力に1回だけ表示されます。修飾名でソーステーブルのカラムを参照するとエラーになります。

以前のPrestoと比較して、この変更により次のエラーメッセージが発生する可能性があります。それぞれについて、クエリを書き直す方法の例を示します。

エラーメッセージ: Column 'xxx.yyyy' cannot be resolved

エラーを引き起こすコード例:

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

エラーメッセージ: Given correlated subquery is not supported

アップグレード後、相関サブクエリは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_WINDOWに置き換える

このアップデートのためにコードを確認する際に、TD_SESSIONIZEを使用している既存のクエリに対して重要なアップグレードを行うこともお勧めします。TD_SESSIONIZE() 関数は、パフォーマンスの問題と一貫性のない結果のため廃止されました。代替となるPrestoウィンドウ関数TD_SESSIONIZE_WINDOW()は2016年に追加されました。これはTD_SESSIONIZEの問題に対処しています。クエリを書き直すための詳細な手順はこちらにあります:

Presto TD_SESSIONIZE() から TD_SESSIONIZE_WINDOW() への移行