🗿

Git for Data「Dolt」というDBの話

2022/01/01に公開

ここ最近、何やらデータベースの相談をされることが何やら多くなってきたmasamikiです。

今、とあるプロダクトの開発をしようと、要件まとめたり設計したりたりしてるのですが、この仕組みをやるためには…version管理いるなぁ…gitが欲しいなぁ……となってます。

そして、調べてみたところ、2年も前のものですがこんな記事を見つけました。
https://www.dolthub.com/blog/2020-03-06-so-you-want-git-for-data/

「DoltとDoltHubが我々の結論だ」とおっしゃってます。

Doltとは

Doltは、Gitリポジトリと同じように、フォーク、クローン作成、ブランチ、マージ、プッシュ、プルできる最初で唯一のSQLデータベースです。(← by Google翻訳)

おぉ、まさしく、そのままんま、これだ。

他にも、GitRows とかも使えそうかな…と思ってみていたものの、どうやら今の要件にあうのあはDoltっぽそう。

上記事だと、他にもdata.world(Microsoft Dataverseみたいなもんですかね…?)やDVC(機械学習プロジェクト用のオープンソース
バージョン管理システム)とかまだ触ったことないものも記載されていたので、ちょっとどっかで試してみたいなと思いながら、今回はDoltを触ってみます。

Qiitaでも2020年に記事にしてる方がいらしゃいますね → RDBのデータの構成管理ができるDoltとは

インストール

ここ以降の話は、大体↓に書いてあるので、原文みてやりたいかたはどうぞ。
https://docs.dolthub.com/introduction/what-is-dolt

macはhomebrewで入れられるので、コマンドはこれだけ。(mac前提で進めます)

brew install dolt

サーバーの起動

以下のコマンドで実行します。

dolt sql-server

あ、3306がすでに別のサービスに使われてたので、ポートを3307に変えてやり直し。

dolt sql-server -P 3307

接続

DoltはMySQLのclientでアクセスできるらしく(portもdefaultで3306)、接続するならこんな感じ。

mysql --host 127.0.0.1 --port 3306 -uroot

そのまま使えるのいいですね。

データベース作成

データベースの作成もMySQLと同じ。

create database test;

表示も同じ。(client一緒ですからね。)

+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
+--------------------+
2 rows in set (0.00 sec)

テーブル作成

もう、MySQLと同じなので書く必要もなさそうですが、こんな感じ。

use test;
create table employees (
    last_name varchar(255), 
    first_name varchar(255), 
    title varchar(255), 
    date_started date, 
    primary key(last_name, first_name)
);
+-----------+
| Table     |
+-----------+
| employees |
+-----------+
1 row in set (0.00 sec)

コミット

そう、ここからが知りたいところです。
gitライクな操作、どうなるのか?

まずはcommitから。

commitには、dolt_commit というのを使います。コマンドはこんな感じ。

select dolt_commit('-a', '-m', 'Created employees table');

-aオプションはすべての変更済みのテーブル、-mオプションはメッセージと、これもgitと同じですね。

そして、selectを実行の為に使うみたいです。

+----------------------------------------------------+
| dolt_commit('-a', '-m', 'Created employees table') |
+----------------------------------------------------+
| h99ip189o6nuad7f8c8951654o9eu86a                   |
+----------------------------------------------------+
1 row in set (0.01 sec)

データの挿入とコミットだとこんな感じ。

insert into employees values ('Sehn', 'Tim', 'CEO', '2018-08-06');
select dolt_commit('-a', '-m', 'Inserted Tim Sehn, CEO');
+-----------+------------+-------+--------------+
| last_name | first_name | title | date_started |
+-----------+------------+-------+--------------+
| Sehn      | Tim        | CEO   | 2018-08-06   |
+-----------+------------+-------+--------------+
1 row in set (0.00 sec)
+---------------------------------------------------+
| dolt_commit('-a', '-m', 'Inserted Tim Sehn, CEO') |
+---------------------------------------------------+
| j6iv0hmmho21oe1uh3pnit6i3vf5p3jc                  |
+---------------------------------------------------+
1 row in set (0.01 sec)

ブランチきる

ブランチをきるというか、checkoutは dolt_checkout でやるようです。
これも、-bオプションで新しいブランチを作成しながらcheckoutするみたいです。
(switchじゃないのか)

select dolt_checkout('-b', 'hoge');

すると以下のようなレスポンスが返ってきます。

+-----------------------------+
| dolt_checkout('-b', 'hoge') |
+-----------------------------+
|                           0 |
+-----------------------------+
1 row in set (0.01 sec)

インサートして

insert into employees values ('Son', 'Aaron', 'Founder', '2018-08-06');
+-----------+------------+---------+--------------+
| last_name | first_name | title   | date_started |
+-----------+------------+---------+--------------+
| Sehn      | Tim        | CEO     | 2018-08-06   |
| Son       | Aaron      | Founder | 2018-08-06   |
+-----------+------------+---------+--------------+
2 rows in set (0.01 sec)

commit。

select dolt_commit('-a', '-m', 'Inserted Adron, Founder');
+----------------------------------------------------+
| dolt_commit('-a', '-m', 'Inserted Adron, Founder') |
+----------------------------------------------------+
| r9rrob8t4jct6kucsmpdt238emnqjcec                   |
+----------------------------------------------------+
1 row in set (0.03 sec)

mainに戻って

select dolt_checkout('main');

見る。

+-----------+------------+-------+--------------+
| last_name | first_name | title | date_started |
+-----------+------------+-------+--------------+
| Sehn      | Tim        | CEO   | 2018-08-06   |
+-----------+------------+-------+--------------+
1 row in set (0.01 sec)

おぉ、消えてる。

マージ

hogeブランチに入れたデータをマージします。

select dolt_merge('hoge');
+--------------------+
| dolt_merge('hoge') |
+--------------------+
|                  1 |
+--------------------+
1 row in set, 1 warning (0.01 sec)

見る。

+-----------+------------+---------+--------------+
| last_name | first_name | title   | date_started |
+-----------+------------+---------+--------------+
| Sehn      | Tim        | CEO     | 2018-08-06   |
| Son       | Aaron      | Founder | 2018-08-06   |
+-----------+------------+---------+--------------+
2 rows in set (0.00 sec)

おぉ、マージされた。

log

commitのログをみるのもgitと同じくlogを使うみたいです。
ただ、これまのクエリと異なり、テーブルを参照するようなクエリになるもよう。

select * from dolt_log;
+----------------------------------+---------------------+----------------------+-------------------------+----------------------------+
| commit_hash                      | committer           | email                | date                    | message                    |
+----------------------------------+---------------------+----------------------+-------------------------+----------------------------+
| r9rrob8t4jct6kucsmpdt238emnqjcec | Dolt System Account | doltuser@dolthub.com | 2022-01-01 05:09:34.799 | Inserted Adron, Founder    |
| j6iv0hmmho21oe1uh3pnit6i3vf5p3jc | Dolt System Account | doltuser@dolthub.com | 2022-01-01 04:09:56.746 | Inserted Tim Sehn, CEO     |
| h99ip189o6nuad7f8c8951654o9eu86a | Dolt System Account | doltuser@dolthub.com | 2022-01-01 04:08:04.903 | Created employees table    |
| 1gehtq3ftbd7a350s5prern2orm1gepq | Dolt System Account | doltuser@dolthub.com | 2022-01-01 04:01:24.411 | Initialize data repository |
+----------------------------------+---------------------+----------------------+-------------------------+----------------------------+

Dolt SQL Functions一覧

このdolt_hogeのSQLは、Dolt SQL Functionsという名前でのようですが、こんなものが用意されているみたいです。
gitと同じなので、Fucntionの内容はイメージしやすいですね。

dolt_commit()
dolt_add()
dolt_checkout()
dolt_merge()
dolt_reset()
dolt_push()
dolt_fetch()
dolt_pull()
dolt_merge_base()
hash_of()

Dolt テーブル一覧

logもそうでしたが、Doltは以下のようなテーブルを持っていて、システムとしての情報が保管されています。

dolt_branches
dolt_commit_diff
dolt_diff
dolt_docs
dolt_history
dolt_commit_ancestors
dolt_log
dolt_status
dolt_conflicts
dolt_conflicts_$tablename
dolt_constraint_violations
dolt_constraint_violations_$tablename
dolt_procedures
dolt_schemas
dolt_remotes

なのでブランチを見たいときは、

select * from dolt_branches;
+------+----------------------------------+---------------------+------------------------+-------------------------+-------------------------+
| name | hash                             | latest_committer    | latest_committer_email | latest_commit_date      | latest_commit_message   |
+------+----------------------------------+---------------------+------------------------+-------------------------+-------------------------+
| hoge | r9rrob8t4jct6kucsmpdt238emnqjcec | Dolt System Account | doltuser@dolthub.com   | 2022-01-01 05:09:34.799 | Inserted Adron, Founder |
| main | r9rrob8t4jct6kucsmpdt238emnqjcec | Dolt System Account | doltuser@dolthub.com   | 2022-01-01 05:09:34.799 | Inserted Adron, Founder |
+------+----------------------------------+---------------------+------------------------+-------------------------+-------------------------+

コンフリクト

気になる大きな問題は、conflictどうするのかですよね。

Hogeの追加

select dolt_checkout('-b', 'hogehoge');
UPDATE employees SET title='CTO';
select dolt_commit('-a', '-m', 'Hoge');
select dolt_checkout('main');

Fugaの追加

select dolt_checkout('-b', 'fugafuga');
UPDATE employees SET title='CFO';
select dolt_commit('-a', '-m', 'Fuga');
select dolt_checkout('main');

Hogeのマージ

select dolt_merge('hogehoge');
select dolt_commit('-a', '-m', 'Merge');
+------------------------+
| dolt_merge('hogehoge') |
+------------------------+
|                      1 |
+------------------------+
1 row in set (0.02 sec)

Fugaのマージ

select dolt_merge('fugafuga');
ERROR 1105 (HY000): merge has unresolved conflicts. please use the dolt_conflicts table to resolve

エラーが返るようです。

select dolt_commit('-a', '-m', 'Merge');
ERROR 1105 (HY000): error: the table(s) employees in conflict

commitもできないようにちゃんとなってます。
では、tableを拝見。

select * from dolt_conflicts;
ERROR 1105 (HY000): merge has unresolved conflicts. please use the dolt_conflicts table to resolve

あれ?
これでコンフリクトの数みたいなのが出るはずなのですが、でない……
詰んだ…

とりあえず、conflictしたものは、dolt_conflicts_{{テーブル名}}に入るそうで、現時点のブランチを正とするならば、コンフリクトを削除すればいいとのこと。

DELETE FROM dolt_conflicts_employees;
select dolt_commit('-a', '-m', 'Merge');
+----------------------------------+
| dolt_commit('-a', '-m', 'Merge') |
+----------------------------------+
| 199augn48g1bkjftog7rfn67oa5s7pe4 |
+----------------------------------+
1 row in set (0.03 sec)

解消できたようです。

ちょっと、コンフリクトの内容見れないのは困りましたね…
コンフリクトの解消方法もコードと違って難しそう。

プログラム言語

mysql clientに対応してることもあり(コンフリクトのレスポンスをうまくえられませんでしたが…)、大抵の言語は、mysqlのライブラリをそのまま用いればいいようです。
例えば、Goであれば、go-sql-driver/mysql packageが使えます。

CLI

SQLでなくとも、Dolt自体のCLIでいろいろと操作もできるみたいです。

commitであれば、こんな感じ。

dolt commit [options]

まんまgitのコマンドみたいな感じなんで、これもわかりやすいですね。

感想

ちょっと不備を感じましたが(mysqlのclientのバージョンとかのせいな気もしますが)悪くはないなぁと。

データの登録の際にcommitという処理をしておく必要があったり(変更をため込んでも別にいいと思いますが)、コンフリクトの解消が少しやっかいそうというのはあり、ただのDBよりも少し複雑にはなりますが、ブランチというような概念があるといい機能って意外と世の中にはあると思いますし、使いどころが大分ありそうなDBだと思いました。
開発用の環境にも使えそうですよね。大がかりなMigrationをテストしたい時とかも、ブランチ切れるなら遠慮無く流して、またすぐに戻せますしね。コードのブランチにあわせてDBのブランチも変えられるとかはありかなと。(dumpとかスナップショット戻すより楽)

今のプロダクトに採用するかどうかはわからないですが、どっかで利用してみたいなと思います。

Discussion