Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PostgreSQL のイケてるテクニック7選

1,111 views

Published on

第10回PostgreSQL アンカンファレンス発表資料

Published in: Technology
  • Be the first to comment

PostgreSQL のイケてるテクニック7選

  1. 1. PostgreSQL の イケてるテク 7選 2019/02/02 第10回 PostgreSQLアンカンファレンス
  2. 2. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 1自己紹介 Tomoya Kawanishi a.k.a. @cuzic 元 関西電力勤務 全社的に標準DBとして PostgreSQL を選定。導入を推進。 エネチェンジ株式会社 チーフエンジニア 電力会社、ガス会社を切り替えるなら、エネチェンジ経由で! 一般家庭も!法人も! WEBアプリケーション開発が主。 Ruby関西の中の人 発表者として登壇くださる方、あとで声かけください。 大手町.rb の中の人 毎月 大手町.rb の開催を予定 東京駅、各線大手町駅から直結! Ruby の初級者がメインターゲット
  3. 3. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 今日のテーマ 私は DB エンジニアではないので、 利用者側の内容ばかりになっています。 Timestamp の範囲の表現 Coalesce 関数とTimestamp型の 'infinity' tstzrange 共通テーブル式(Common Table Expressions) VALUES を使った subquery ラテラルジョイン 、json_array_elements、WITH ORDINALITY AS 豊富な集約関数 統計処理 ltree 型 2
  4. 4. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 Timestamp の範囲 1/3 キャンペーン情報をDBで管理 2月1日~2月28日までのキャンペーンなどがよくある 単純な実装例 有効なキャンペーンを取り出す SQL ちょっと読みにくい 3 id : キャンペーンの ID start_at : timestamp 型 end_at : timestamp 型 SELECT * FROM campaigns WHERE (start_at IS NULL OR start_at < now() ) AND (end_at IS NULL OR now() < end_at);
  5. 5. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 Timestamp の範囲 2/3 OR と AND の組合せは、脳への負担が重い AND だけだと理解しやすい coalesce : 第1引数が null のとき、第2引数の値を返す デフォルト値を設定できる関数と思うと理解しやすい 自動的に型変換される。 '-infinity'::timestamptz と同じ '-infinity' は無限の過去。 'infinity' は無限の未来 4 SELECT * FROM campaigns WHERE (start_at IS NULL OR start_at < now() ) AND (end_at IS NULL OR now() < end_at); SELECT * FROM campaigns WHERE coalesce(start_at, '-infinity') < now() AND now() < coalesce(end_at, 'infinity')
  6. 6. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 Timestamp の範囲 3/3 tstzrange で日時の範囲型を1つの列で表現できる [, ] で閉区間(境界を含む)、 (, ) で開区間(境界を含まない) @> で、簡潔に contains の判定が可能 gist の index 設定も可能で SQL も高速化可能 5 SELECT * FROM campaigns WHERE duration @> now(); id : キャンペーンの ID duration : tstzrange 型 INSERT INTO campaigns ( id, duration ) VALUES (1, '[-infinity, infinity]'), (2, '[-infinity, 2019-02-01)');
  7. 7. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 共通テーブル式(Common Table Expressions) 6 WITH provider_order_count AS ( SELECT provider_id, count(1) AS count FROM orders GROUP BY provider_id HAVING count(1) > 1000 ) SELECT b.key, count FROM provider_order_count AS a, providers AS b WHERE a.provider_id = b.id ここに参加してる人は 全員熟知してる? 私は最初かなり感動しました。 上から下に処理順に書ける、 読める。 これまで、FROM のところに 書いていたのと比べ 格段に維持運用しやすい
  8. 8. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 LATERAL ジョイン、json_array_elements、 WITH ORDILALITY LATERAL SQL 界の forループ 左側の各行に対して 右側のサブクエリを 実行し、ジョインする この場合、LATERAL は 省略可 (後続が関数だから) json_array_elements JSON の配列を 行として展開できる WITH ORDINALITY 順位を一緒に返す ->> JSON オブジェクトの 値を取り出す 7 WITH recent_histories AS ( SELECT * FROM try_histories ORDER BY id DESC ), chosen_plans_json AS ( SELECT id, t.chosen_plan, t.idx FROM recent_histories AS rh, LATERAL json_array_elements(rh.chosen_plans) WITH ORDINALITY AS t(chosen_plan, idx) ), SELECT id, idx, chosen_plan->>'provider_key' AS provider_key, chosen_plan->>'plan_key' AS plan_key, chosen_plan->>'area_key' AS area_key FROM chosen_plans_json;
  9. 9. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 CTE のサブクエリとして VALUES を書く CTE のサブクエリ として VALUES も 書ける 定数を SQL 内で 書ける 処理を AP サーバから DB サーバに移せる 8 WITH order_type_count AS ( SELECT type_id, count(1) AS count FROM orders GROUP BY type_id ), contract_types(type_id, name) AS ( VALUES (1, 'electric_gas'), (2, 'gas'), (3, 'electric') ) SELECT b.name, a.count FROM order_type_count AS a, contract_types AS b WHERE a.type_id = b.type_id
  10. 10. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 豊富な集約関数、ウィンドウ関数 集約関数 array_agg : 配列として集約 bool_and: 全部の値が true だと true。1つでも false だと false bool_or :全部の値が false だと false。 json(b)_agg : JSON の配列として集約 json_object_agg : JSON オブジェクトとして集約 string_agg : 文字列を区切り文字で連結して集約 FILTER 節 いままでの複雑な SQL が FILTER を使うととてもカンタンに書ける! pivot テーブル的なタテのものを横にしたいときとかにベンリ 9 SELECT count(1) FILTER(WHERE type_id = 1) AS electric_gas_count, count(1) FILTER(WHERE type_id = 2) AS gas_count, count(1) FILTER(WHERE type_id = 3) AS electric_count FROM orders;
  11. 11. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 PostgreSQL で統計処理 10 SELECT COUNT(1), -- カウント AVG(price), MIN(price), MAX(price), -- 平均、最小、最大 -- メディアン(中央値) PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY price) AS median_price, -- 標準偏差 STDDEV_SAMP(price) AS stddev_price, -- 25% パーセンタイル PERCENTILE_CONT(0.25) WITHIN GROUP(ORDER BY price) AS first_quartile, -- 75% パーセンタイル PERCENTILE_CONT(0.75) WITHIN GROUP(ORDER BY price) AS third_quartile, -- 相関係数 CORR(price, room_number) AS corr_rm, CORR(price, lower_status_percentage) AS corr_lstat, CORR(price, student_teacher_ratio) AS corr_ptratio FROM boston_housing_data; PostgreSQL だけで、さまざまな統計処理が可能 標準偏差、メディアン、パーセンタイル、相関係数 パーセンタイルを計算するときは並び順を WITHIN GROUP で指定する
  12. 12. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 ltree 型 PostgreSQL 標準拡張にある型の1つ 階層的なラベルデータを表現可能 @>、<@ 包含関係 ~ 経由する場合 gist の index の作成もできる 11 CREATE EXTENSION ltree; Top Top.Science Top.Science.Astronomy Top.Science.Astronomy.Astrophysics Top.Science.Astronomy.Cosmology Top.Hobbies Top.Hobbies.Amateurs_Astronomy Top.Collections Top.Collections.Pictures Top.Collections.Pictures.Astronomy Top.Collections.Pictures.Astronomy.Stars Top.Collections.Pictures.Astronomy.Galaxies Top.Collections.Pictures.Astronomy.Astronauts -- Top.Science の子孫のみを抽出する SQL SELECT * FROM "ltree_tests" WHERE (path <@ 'Top.Science') -- Astronomy を経由する場合を抽出する SQL SELECT * FROM "ltree_tests" WHERE (path ~ '*.Astronomy.*')
  13. 13. 第10回PostgreSQL アンカンファレンス 「PostgreSQL のイケてるテク7選」 おわりに 私自身の仕事はDB専門ではなく WEBアプリケーション開発がメインです。 そのため、DBを利用する側に特化して 個人的にイケてると思う PostgreSQL の機能を いくつか紹介しました。 みなさんの参考になれば、さいわいです。 12
  14. 14. ご清聴ありがとう ございました

×