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.

第51回NDS PostgreSQLのデータ型 #nds51

3,496 views

Published on

・PostgreSQL特有のデータ型の紹介
・プログラムからどのように利用するか

Published in: Technology
  • Be the first to comment

  • Be the first to like this

第51回NDS PostgreSQLのデータ型 #nds51

  1. 1. PostgreSQLのデータ型 #nds51 @civic
  2. 2. 自己紹介 • NDS管理人 @civic • 最近は低温調理にハマっています
  3. 3. 40歳超えたら 自己紹介は30秒以下にしろ!
  4. 4. 今日話す内容 • PostgreSQL特有のデータ型の紹介 • プログラムからどのように利用するか そういえば聞いたことがある・・・ 「自分の知らない分野の話をすると非常に学びになる」 という
  5. 5. 経緯 • 数値・文字列・日付ぐらいしか使ってないぞ • ざっとドキュメントを眺めていた • 使ったことのないデータ型がたくさんあるぞ • 特にPostgreSQLはデータ型が多い • もっとデータベースの機能を使ったほうが良いのでは ? • 日付を8桁の文字で保持→DATE型 • ???→PostgreSQLが用意するデータ型
  6. 6. 質問 • みなさんがメインで使っているRDBMS製品は? • postgresql • mysql • sqlserver • oracle
  7. 7. 各種RDBMSが対応する データ型を比較
  8. 8. データ型の対応を調べてみた postgresql mysql sqlserver oracle 数値 文字列 日付 論理値 幾何データ XML JSON バイナリ ....
  9. 9. 思ったほど 大差なかった・・・
  10. 10. 思ったより大差なかった・・・ • PostgreSQLにしかないと思っていた型 • 最近のバージョンではサポートしている • 例:JSON • postgresql 9.2 • mysql 5.7 • sqlserver 2016
  11. 11. PostgreSQL特有 ってほどでもないけど 面白そうなデータ型の紹介
  12. 12. PostgreSQL データ型 #nds51 @civic 特有ってほどでもないけど面白そうな
  13. 13. json / jsonb型
  14. 14. JSON(JavaScript Object Notation) { "foo": 123, "bar": "Hello World", "hoge": [1, 2, 3] } JSONデータ
  15. 15. json型 • postgresql 9.2以降 • mysql 5.7 • sqlserver 2016 • oracle チェック制約のみ CREATE TABLE mytable( id integer, info json );
  16. 16. jsonb型 • postgresql 9.4以降 • jsonをバイナリで保持 • 検索効率向上 • 各種関数・演算子のサポート • インデックスサポート CREATE TABLE mytable( id integer, info jsonb );
  17. 17. 使いどころ
  18. 18. 使いどころ • 入力によって柔軟な構造が必要なケース • アドレス帳の追加属性とか?
  19. 19. JSONが使えるなら 1列でいいじゃん!
  20. 20. なんでもJSONにするのは危険 • 1つの列に複数の意味のデータを入れるべきではない • 制約が使えない・外部キーが使えない • クエリが複雑になる • 検索や関連に使われないデータのみに使用したい 参考: PostgreSQLのアンチパターン : 何でもかんでもjsonに入れる https://yakst.com/ja/posts/2445
  21. 21. 使用例
  22. 22. 本の情報 books CREATE TABLE books( id integer PRIMARY KEY, name text, price integer, info jsonb ); INSERT INTO books VALUES (1, 'book1', 45745, '{"format": "text", "tags": ["english","game","
  23. 23. 検索 SELECT * FROM books WHERE info @> '{"format": "pdf"}'::jsonb; formatがpdfの本を検索 @> 包含演算子 JSONパス・値を保持するか
  24. 24. 感想 • textにjson入れるよりはJSON検証も行われる • インデックスや各種関数、演算子が使えて便利 • id, key, valueだけのテーブル(EAV)よりマシか • 外部キーは絶対マズい • 検索条件に使うのは要件次第か 用法用量を守ろう
  25. 25. 範囲型
  26. 26. 範囲型 • 数値や日付の範囲を表すデータ型 • postgresql 9.2以降 • mysql • sqlserver • oracle PostgreSQL特有! start end
  27. 27. 範囲型 • 数値 • int4range: 4バイト整数範囲 • int8range: 8バイト整数範囲 • numrange: 実数範囲 • 日付 • tsrange: 日付時刻範囲 • tszrange: 日付時刻範囲(タイムゾーンつき) • daterange: 日付範囲
  28. 28. 使いどころ
  29. 29. 2列で持っていたデータを1列で • from, to, start, end • 開始よりも終了が大きいという整合性
  30. 30. 境界が明確 • 3以上7以下(閉じた境界) • '[3, 7]'::int4range • 3以上7未満(開いた上限) • '[3, 7)'::int4range • 3以上(境界のない上限) • '[3, ]'::int4range 3 7 3 7 3
  31. 31. 重なりや含有をチェックする演算子 • 含有 '[10, 20]'::int4range @> 14 • 重なり '[10, 20]'::int4range && '[15, 30]'::int4range 10 20 14 10 2015 30
  32. 32. インデックスもサポート
  33. 33. 使用例
  34. 34. 予約テーブル • EXCLUDEの排他制約で予約の重複を防ぐ制約 CREATE TABLE reservation( during daterange, EXCLUDE USING GIST(during WITH &&) ); INSERT INTO reservation VALUES('[2017-03-10, 2017-03-12]'); INSERT INTO reservation VALUES('[2017-03-11, 2017-03-13]'); --重なりがあるのでエラー ↑duringの重なりの排他
  35. 35. めっちゃ便利!
  36. 36. 2つのデータ型を紹介しました
  37. 37. プログラムから どう利用するか?
  38. 38. プログラミング言語から • プログラミング言語からDBを使うときには様々な ライブラリを通している • DBアクセス用API • ORマッパーなどの便利ライブラリ • 標準APIは各種DBの最小公倍数的な機能 • JDBC APIで提供されるデータ型にJSONはない
  39. 39. Javaの例 PostgreSQL Java Application JDBC Driver for PostgreSQL JDBC API EclipseLinkJPA PostgreSQL特有の機能は ネイティブなところまで
  40. 40. どうやって使うのか • ネイティブ対応しているレイヤーを使用 • JDBC for PostgreSQL • テキスト経由で受け渡し→SQLで型変換 • PostgreSQL方言 • ライブラリ側の対応次第
  41. 41. 具体的に考えてみる • jsonb型をJava / Pythonから利用 CREATE TABLE json_test( id integer, info jsonb ) id info 1 {"a": 100, "b": "Hello"} 2 {"a": 200, "b": "World"}
  42. 42. Javaの場合 https://github.com/civic/postgresql-java-json
  43. 43. 検証ケース • SELECTとINSERTについて考える • 低レベルAPI → JDBC API • 高レベルAPI → JPA(永続化標準API)
  44. 44. JDBC API (低レベルAPI) resultSet.getString("info"); // {"a": 100, "b": "Hello"} SELECT ResultSet#getStringで文字列として取得可能
  45. 45. JDBC API (低レベルAPI) INSERT PGobjectを使用。 ※postgresqlドライバの機能 import org.postgresql.util.PGobject; PGobject pgobj =new PGobject(); pgobj.setValue(json_string); //json文字列 pgobj.setType("jsonb"); preparedStatement.setObject(1, pgobj); Java的にはベンダー製パッケージのimportは ちょっと抵抗がある
  46. 46. JDBC API (低レベルAPI) INSERT SQL文内でキャスト PreparedStatement ps =conn.prepareStatement( "INSERT INTO json_test(info) VALUES(jsonb(?))" ); ps.setString(1, json_string); //json文字列
  47. 47. JPA (高レベルAPI) SELECT / INSERT Converterを作成すれば SQLデータ型とJavaデータ型を相互変換できる @Entity @Table(name = "json_test") public class JsonTest implements Serializable { // ... 中略 ... @Column(name = "info") @Convert(converter = JsonbConverter.class) private String info;
  48. 48. Pythonの場合 https://github.com/civic/postgresql-python-json
  49. 49. Pythonの例 PostgreSQL Python Application psycopg2DB API SQLAlchemy PostgreSQL特有の機能は ネイティブ対応なところまで libpq
  50. 50. 検証ケース • SELECTとINSERTについて考える • 低レベルAPI → psycopg2 • 高レベルAPI → SQLAlchemy
  51. 51. psycopg2 (低レベルAPI) cur.execute( "SELECT info FROM json_test WHERE id=1" ) row = cur.fetchone() print(row[0]) # {'b': 'Hello', 'a': 100} SELECT 何もしなくても、dict(辞書型)として取得できる
  52. 52. psycopg2 (低レベルAPI) INSERT psycopg2.extras.Jsonを使用し、dict→Json from psycopg2.extras import Json #json objectで更新 cur.execute( "INSERT INTO json_test(info) VALUES(%s)", [ Json({"a":30, "b": "update"}) ] )
  53. 53. psycopg2 (低レベルAPI) INSERT SQL文内でキャスト。 import json # dictを文字列化してSQLに渡す cur.execute( "INSERT INTO json_test(info) VALUES(jsonb(%s))", [ json.dumps({"a":30, "b": "update"}) //dict→str ] )
  54. 54. SQLAlchemy (高レベルAPI) SELECT / INSERT SQLAlchemyは至れり尽くせり。 各DBベンダー用方言(dialect)が用意されている。 from sqlalchemy.dialects.postgresql import JSONB class JsonTest(Base): __tablename__ = 'json_test' id = Column(Integer, primary_key=True) info = Column(JSONB) # JSONB型の列と宣言 ...
  55. 55. まとめ
  56. 56. まとめ • PostgreSQL特有のデータ型が便利そう 正規化を失わないように • プログラミング言語からもpg特有の型は使えそう • Java • 標準APIのままでは使いにくい • ベンダー実装の機能を使うか型変換で • Python • ダックタイピングできるのでJavaほど厳しくない • SQLAlchemy便利
  57. 57. 参考 • PostgreSQL 9.6.2文書 • PGCon2014 JSONB データ型を使ってみよう • Oracle® Database SQL言語リファレンス • MySQL 5.7 Reference Manual • データ型 (Transact-SQL) - MSDN - Microsoft • PostgreSQLのアンチパターン : 何でもかんでもjsonに入れる • JPA 2.1 の 新機能 Converter まとめ • Psycopg - PostgreSQL database adapter for Python

×