🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Q&A

解決済

2回答

2868閲覧

PostgreSQLでWhere句の内容に応じて参照するテーブルを動的に変更したい

naotel

総合スコア6

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

0グッド

0クリップ

投稿2020/11/25 09:47

編集2020/11/25 12:06

背景

常時、データ(タイムスタンプのカラムがあるデータ)がインサートされるテーブルがあり、そのテーブルには直近1年以内のデータしか保持できない設計としています。
そのため1年以上前のデータはcsv化され別のストレージに保存される仕組みとしています(テーブル容量削減の意図)

しかし、運用上、1年以上前のデータを参照することがあります。
このとき、そのテーブルにアクセスした際に1年以上前のデータを参照する際にはcsvからデータを取得する運用としたいです、

環境

  • PostgreSQL Ver

    9.5

現状できていること

file_fdwを使って外部ストレージに保存されたcsvをテーブルとみなしてデータを取得することはできています。

やりたいこと

Where句でタイムスタンプの値が1年以上前を参照した際に、参照するテーブルを動的に変更したいです。
手段としては拡張機能を検討していますが、実現手法のイメージができていません。
全体構造は以下のような形を想定しています
イメージ説明

  1. 直近一年以内のデータを参照するときには、PostgreSQL内のテーブルからデータを参照したいです。

イメージ説明

  1. 一年以上前のデータを参照するときには、外部ストレージのcsvデータを参照したいです。

イメージ説明

ただし、問い合わせるクエリ文(青四角部)のFrom句は、直近一年分のデータを参照するときと一年以上前を参照するときで変更できません
これは問い合わせ側の制約になります。

例えば実行日時を2020-11-04 00:00:00とした際に以下のクエリを受け取るとします。

Select * From TABLE Where ‘2019-11-04 00:03:00’ >= _timestamp and _timestamp >= '2019-11-04 00:00:00'

この場合、一年以上前のデータになるため、From句を変更して外部テーブルにアクセスする必要があります。
また、csvは毎分ごとに作成されるものになるため、上記のようなWhere句の場合以下の3つのcsvにアクセスする必要があります。

  • アクセスする必要のあるテーブル名

TABLE_2020110403
TABLE_2020110402
TABLE_2020110401

現在想定している手法は、拡張機能でアクセスする必要のあるテーブル名のARRAYを作成し、以下の関数によって各テーブルの結果を結合することです。

DROP FUNCTION IF EXISTS csv(csv_names text[]); CREATE OR REPLACE FUNCTION csv(csv_names text[]) RETURNS TABLE( _timestamp timestamp(3) without time zone, _data text ) AS $$ DECLARE csv_name text; Begin FOREACH csv_name IN ARRAY csv_names LOOP RETURN QUERY EXECUTE format('Select * FROM %I', csv_name); END LOOP; END; $$ LANGUAGE plpgsql;

行き詰っているところ

以下の2の手順における、1の手順で受けたクエリのWhere句に応じて、リストを作成する工程で行き詰っています。

1. クエリを受け取る

Select * From TABLE Where ‘2019-11-04 00:03:00’ >= _timestamp and _timestamp >= '2019-11-04 00:00:00'

2. 一年以上前のデータなので、上記のクエリは実行せずに、以下のリストを作成する

[TABLE_2020110403, TABLE_2020110402, TABLE_2020110401]

3. 2のリストを受け取って、関数(csv)に引数として与えて、処理を実行する

Select * FROM csv(ARRAY[‘TABLE_2020110403’, ‘TABLE_2020110402’, ‘TABLE_2020110401’] Where ‘2019-11-04 00:03:00’ >= _timestamp and _timestamp >= '2019-11-04 00:00:00'

拡張機能であればこの処理が実現できるのかもしれませんが、具体的な手法が思いつきません。

なにかいい手法があればご教授いただけますと幸いです。

設計上の制約

  • 受け取るクエリのFrom句は変更できない
  • PostgreSQLのVerを変更することはできない

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

そのため1年以上前のデータはcsv化され別のストレージに保存される仕組みとしています(テーブル容量削減の意図)

この目的の為なら、テーブル・パーティショニングにするだけで目的は果たせると思います。
外部ストレージにテーブルスペースを定義しそこに古いデータを格納するようにすれば良いだけで、わざわざCSVに変換する必要もないので、file_fdwを使用する事もないです。

postgresのパーティショニングは複数の実体のテーブルを一つのテーブルに見せかけるものです。
パーティショニング : 用途と利点
5.10. パーティショニング

現状の構成でパーティショニングできれば、SQL上は一つのテーブルにアクセスするだけになります。

ここからはアイデアで可能かどうかは、分かりません。

パーティショニングは、定義だけの親テーブル構造を実体の子テーブルに継承する仕組みです。
この子テーブルに外部テーブルが指定できれば、外部テーブル混在型のパーティショニングになります。
但し、外部テーブルを含んだ検索になった場合の性能には期待できないと思いますが。

投稿2020/11/25 13:34

sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

naotel

2020/11/30 08:36 編集

sazi様 ご回答ありがとうございます。 > この子テーブルに外部テーブルが指定できれば、外部テーブル混在型のパーティショニングになります CREATE FOREIGN TABLEにINHERITSのオプションができようできたため、子テーブルに外部テーブルを指定したパーティショニングが実現できました。 > 但し、外部テーブルを含んだ検索になった場合の性能には期待できないと思いますが。 複数テーブルをまたぐ、且つ外部ストレージの検索処理になるため、ある程度のパフォーマンス低下は仕方ないと考えています。 ここは外部テーブルを含んだ検索でパフォーマンス評価を行い、要件を満たすかどうかで判断していきたいと思います。
guest

0

普通にUnionしたらいいかと。
参考

あと、

以下のようにFrom句を変更したいです

実行するクエリのFrom句は変更できない

が矛盾してます。

投稿2020/11/25 10:40

szk.

総合スコア1400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sazi

2020/11/25 11:26

リンク先にはunionではなくて、パーティションについてですけど? パーティションのアイデアで回答しようとしたけど、この回答にコメントした方が良いのかな?
naotel

2020/11/25 12:09 編集

To:szk.様 回答ありがとうございます。 矛盾している箇所を修正しました。 修正前)実行するクエリのFrom句は変更できない 修正後)受け取るクエリのFrom句は変更できない また、行き詰っているところを明確化しました。
naotel

2020/11/25 12:11

To:sazi様 sazi様がご覧になったときと質問文を少し修正しております。 パーティションのアイデアがどういったものか教えていただけますでしょうか。
szk.

2020/11/25 12:48

saziさん 別途回答いただいた方がいいかと思います、パーティションに関して回答したつもりはなかったのでm()m どちらかというと、file_fdw使ってunionできるというところの参考でした。 naotelさん 詳細な記載ありがとうございます、unionで解決が難しいというのであれば、 saziさんからの回答を待っていただいた方がいいかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問