タイムトラベル：ビットタイムデータによる2次元の時間

<font color="Grey">*[Time travel: two-dimensional time with bitemporal data](https://aiven.io/blog/two-dimensional-time-with-bitemporal-data)の翻訳です。*</font>

2023年4月27日

# タイムトラベル：ビットタイムデータによる2次元時間

同じデータ、複数の変数：新しい方法でデータを探索することを学ぶ

従業員レコードのように、ある従業員が現在の従業員なのか、それとも退職した従業員なのかを表示できるようなものを、どのように実装したらよいかと考えたことはないだろうか。ほとんどの標準的なデータベースを使用すると、これは面倒になる可能性があります：結局、従業員のステータスが変更されるたびに、データベースに新しい行を追加する必要があります。


ビットタイムデータは、1つのレコードを更新し、そのレコードのステータスが時間と共に変化するのをクエリできるようにすることで、この問題を解決することができます。これにより、データベースに適した方法ではなく、実際のビジネスに対応した方法でデータベースをモデル化することができます。


Postgresでビットタイムデータモデルを実装する方法については、ゲスト投稿者であるHenrietta (Hettie) Dombrovskaya氏の投稿をお読みください！


## ビットタイムデータとは？


もしあなたがビットタイムデータという表現に初めて出会ったとしたら、戸惑うかもしれません。時間はすでに4番目の次元と考えられているのに、どうして複数の時間を持つことができるのでしょうか？これ以上混乱する前に、一般的な時間的クエリとデータに時間を追加する方法について説明しましょう。


ビットタイムクエリでは、データベース内の同じレコードにある特定のデータの時間的な変化をクエリすることができます。これは、従業員記録（前述）、オプション取引、監査が必要な環境などで役立ちます。


ある時点のデータを照会できるという考え方は、データベースの黎明期から非常に人気がある。例えば、現在の状態を照会できることに加えて、次のような照会ができたらいいと思いませんか？



```
select first_name, last_name, start_date, salary
FROM EMPLOYEES
WHERE DEPARTMENT='SE'
```

同じクエリを過去の日付*に対して実行できたらいいと思わない？



```
select first_name, last_name, start_date, salary
FROM EMPLOYEES
WHERE DEPARTMENT='SE' AS OF 'Sep-01-2022'
```

あるいは、こんな感じかな：



```
select first_name, last_name, start_date, salary
FROM EMPLOYEES
where department='SE'
WHEN MANAGER ('SE')='John Smith'
```

これらのクエリはすべて、特定の時点（「2022年9月1日」）を参照するか、ある時点（「ジョン・スミスはいつマネージャーになったのか」）に関連しています。これらはすべて非常に便利ですが、通常のSQLではサポートされていません。


時間的データとは、データが時間とともに変化するという考え方です。人事記録はこの例で、従業員の会社での地位（雇用されている、雇用されていない）は時間と共に変化します。


一時的データのもう一つの使用例は監査である。過去6ヶ月間の収益を示す財務レポートがあるとします。昨日の数字がどのようなものであったかは分かっている。今日、同じレポートを実行したところ、過去1ヶ月の数字が違っていた。


何が起こったのか？どうやら誰かがデータベースの数字を変更したようだ。もし賢明であれば、監査テーブルとトリガーを用意し、過去のテーブルのすべての変更を記録することで、このケースを調査し、いつ変更が行われたかを突き止めることができるだろう。もしそうでなければ、深刻な問題を抱えることになる。


しかし、過去にさかのぼって1週間前と同じレポートを再実行することはできません。データを別の環境のある時点にリストアするのは時間がかかる作業であり、その場で行うことはできない。


この2つのユースケースは、一時データベースを使うことで実現できる。テンポラル・データベースは、その中のデータを単一の現在の状態ではなく、時間を通して理解する。


長い間、時系列データベースに関する議論は純粋に理論的なものであった。時系列データベースの実装は複雑すぎると考えられていたため、そのような実装は非効率的であったり、スペースがかかりすぎたりすると考えられていた。pg_bitemporal`プロジェクトは、1つの包括的なソリューションで両方の問題に対処することに成功したプロジェクトである。


## ビットタイムデータの仕組み


ビットタイムデータとそのデータベースへの実装は、JohnsonとWeisの[Asserted Versioning Framework (AVF)[](http://assertedversioning.com/)に基づいている。Asserted Versioning Frameworkは、2次元の時間でデータを操作する方法である。


AVFの最大の特徴は、ビット時間性である。ビット時間テーブルの各行は、有効時間とアサート時間という2つの時間区間に関連付けられている。


有効時間は、行に含まれるデータがいつ*有効*であるかを定義する。例えば、"John Doe will become our customer on June 1, 2022 "の有効開始日は2022年6月1日である。終了日がわからないので、このステートメントの有効終了日はずっと先の未来であると仮定することができます。私たちのデータベースでは、有効終了日を2999年1月1日に設定することができます。有効期限は、ジョン・ドウが実際に顧客となるか、顧客でなくなるかという現実のビジネス要件に拘束されます。


Asserted timeは、行のデータが*真*である期間です。例えば、"John Doe will become our customer on June 1, 2022 and will stop being our customer on January 1, 2999" は、2022年5月1日から2999年1月1日まで真である。有効時間とは異なり、アサートされた時間は実世界の要件に基づくのではなく、私たちが観察に関 心がある期間に基づいています。


以上を踏まえると、**ビット時系列挿入**はグラフ上ではこのようになる。無限大の記号は「未来永劫」を意味する。ビットタイムインサートは、有効時間とアサート時間を境界軸として定義されるグラフ上の領域である：


![ジョン・ドウが05-01にデータベースに追加され、06-01にステータスがシルバーに変更されたことを示す図](https://cdn.sanity.io/images/sczeoy4w/production/c48b524c02c2c42d1b91edcfc95e4aa08905886f-3840x918.png?q=80&fit=min&auto=format&dpr=1.5)


ここで、データモデルに追加データ、例えば顧客ステータスがあるとします。「John Doeは2022年6月1日に当社の顧客になり、初期ステータスはSilverです。"は、*2022年5月1日から2999年1月1日まで*真です。


では、John Doeの顧客ステータスを更新してみましょう：「ジョン・ドウは2022年6月1日に当社の顧客となり、初期ステータスはシルバーです。2022年9月15日、John Doeの顧客ステータスはゴールドに更新されました。"


この場合、アサートされた日付はどうなるでしょうか?つまり、異なる状況で真となる3つのステートメントが存在することになります：


* ジョン・ドウは**2022年**年6月1日に**シルバー**の初期ステータスで**当社の顧客となる。" は **2022年5月1日** から **2999年1月1日** の間に真となる。
* ジョン・ドウは**2022年**月**日現在の顧客であり、初期ステータスは**シルバー**である。
* ジョン・ドウは**2022年6月1日現在**当社の顧客であり、**ステータスは**ゴールド**である」は、**2022年9月15日**から**2999年1月1日**の間に真となる。


このようなレコードの更新は、**ビット時間更新**と呼ばれます。前のレコード(顧客タイプがSilver)は、アサートされた時間に対して真ではなくなっ ていません。現在、2 つの履歴レコードがあり、どちらも 2022 年 9 月 15 日からアサートされています (図 2 を参照)。


![上記の 2 つの履歴レコードを示す画像。現在、John Doeのデータは3つのスライスに分かれている](https://cdn.sanity.io/images/sczeoy4w/production/afeb9dd0a27fcee2dc5363a83dc88f401472109d-3840x2160.png?q=80&fit=min&auto=format&dpr=1.5)


さて、1週間後に間違いを犯し、正しいタイプ変更は*Gold*ではなく*Platinum*であるべきだったと気づいた場合、図3に示すように**時系列修正**を実行することができます。現在、John Doeの顧客タイプは現在*Platinum*であり、以前は*Silver*であった。しかし、9月15日から9月22日の間の任意の日付にさかのぼると、最初はシルバー、次にゴールドという異なる履歴が表示されます。


![画像は、上記のビットタイム修正を示している。ジョン・ドウのデータには現在4つのスライスがある](https://cdn.sanity.io/images/sczeoy4w/production/e28f8da7eb8d73f7dd178e0fc352138fd20c1cc5-3840x1824.png?q=80&fit=min&auto=format&dpr=1.5)


さて、我々のデータについて次のことが言える：


* ジョン・ドウは**2022年**月**日**現在の顧客であり、初期ステータスは**シルバー**である。
* ジョン・ドウは**2022年**月**日現在の顧客であり、初期ステータスは**シルバー**である。
* ジョン・ドウは**2022年6月1日**現在**当社の顧客であり、ステータスは**ゴールド**である" は、**2022年9月15日**から**2999年1月1日**の間、真である。


= John Doe ** is*** our customer as*** June 1, 2022**, with a status of **Platinum**" is true between **September 22, 2023** and **January 1, 2999.**.**.**.


## pg_temporal プロジェクト


では、[pg_bitemporal](https://github.com/hettie-d/pg_bitemporal)プロジェクトを紹介しよう。PostgreSQLベースで動作するAVFの実装である！


GitHubのレポには、ソースコードとSQLファイルが含まれています。docディレクトリにはリファレンスといくつかのPowerPointプレゼンテーションと録音があり、/tutorialディレクトリにはbitemporalチュートリアルがあります。


## なぜPostgreSQLで実装するのか？


ビットタイムデータベースの各行は、基本的に時間経過に伴うデータを格納するテーブルを持つ必要があります。


では、どのようにAVFを実装するのでしょうか？pg_temporalプロジェクトはPostgreSQLを選択しました。


PostgreSQLにはAVFの実装を成功させるために重要な機能がいくつかあります：


* 範囲型**のサポートにより、タイムゾーンの範囲を持つタイムスタンプとして有効かつアサートされたものを定義することができます。さらに、インクルードやオーバーラップのように、タイムレンジに対して複数の操作が定義されている。
* 無限大(+/-)**は、他のどの値よりも大きい特別な値です(すべての数値型とDateTime型に対して機能します)。
* GISTインデックス**と除外制約付きGIST。


## チュートリアルで詳しく学ぶ


[このチュートリアル](https://github.com/hettie-d/pg_bitemporal/tree/master/tutorial)で時間データの使い方を学ぶことができます。このチュートリアルでは、customerテーブル、staffテーブル、orderテーブル、order_lineテーブルを使用して、ビット時系列スキーマの例を構築します。そして、典型的なビジネスプロセスに従います：顧客が注文を行い、その後、いくつかの変更が発生します：顧客が電話番号を変更したり、スタッフが新しい場所に移動したり、商品の価格が変更したりします。このチュートリアルでは、どのような場合に bitemporal update を使用し、どのような場合に bitemporal correction を使用するかを説明します。また、pg_bitemporalを使用することで、様々な履歴クエリを簡単に実行できることも示します。


**マーケティングCTAはこちら？


## 著者について


ヘンリエッタ（ヘティ）・ドンブロフスカヤ（現DRWデータベースアーキテクト）は、35年以上の学術・産業経験を持つデータベース研究者・開発者。ロシアのサンクトペテルブルク大学でコンピューターサイエンスの博士号を取得。サンクトペテルブルグ大学（ロシア）、イリノイ州スコーキーのコンピュータ・システムズ・インスティテュートでデータベースとトランザクションの理論を教えるほか、初心者から上級者までを対象とした複数のデータベース・チューニング・クラスでも教鞭を執る。


Henrietta は PostgreSQL コミュニティで非常に活発に活動しています。2017年1月からシカゴPostgreSQLユーザグループのリーダーを務め、PostgreSQLカンファレンスで定期的に講演を行っています。コミュニティへの貢献には、pg_bitemporalプロジェクト、postgres_airトレーニングデータベース、NORM技術などがある。



Aivenと私たちのサービスに関する最新ニュース、さらにオープンソース全般に関するちょっとした情報を得るには、[月刊ニュースレターを購読](https://aiven.io/newsletter)！Aivenに関する日々のニュースは、[LinkedIn](https://www.linkedin.com/company/aiven/)と[Twitter](https://twitter.com/aiven_io)のフィードでご覧いただけます。