とあるお兄さんの雑記

基本的に技術系の内容を書きますが、何を書くかは私の気分です。

DB2mermaidを使ってMySQLからER図を描く

MySQLからER図を描くとき、面倒臭いとか思ったりしたことはありませんか!!

そんなときにER図を描く手間を減らしてくれる、便利なツールDB2mermaidがあったので簡単に紹介します!

本日の主役
DB2mermaid · PyPI


環境

ツール名 バージョン
MacBook Pro(M1 mac) mac OS Monterey 12.2.1
DB2mermaid 1.0.3
Python 3.10.9
mysqlclient 2.1.1
SQLAlchemy 2.0.7
Docker 20.10.11
Docker Compose v2.2.1
MySQL(Docker Imageで代用) 5.7
DBeaver Community Edition 23.0.0.202303040621

フォルダ構成

最終的に下記のようになりました。

db2mermaid
├── docker
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── mysql
│       ├── 00-sakila-schema.sql
│       ├── 10-sakila-data.sql
│       └── sakila.mwb
└── main.py

環境構築

DB2mermaidの公式を見るとRequireに

  • Python3.10
  • sqlalchemy
  • mysqlclient
  • your (mysql)DB

とあるため、これを参考に環境を作成していきます。

仮想環境の作成

condaで仮想環境を用意しました。

# conda create -n db2mermaid python=3.10 #仮想環境の作成
# conda activate db2mermaid # db2mermaidをactivate

必要なパッケージのインストール

必要なパッケージとしてsqlalchemyやmysqlclientが書かれていますが、パッケージが入っていなくてもおそらくDB2mermaidをインストールするときに勝手に最新版のパッケージを取得してくれるはずです。

# pip install DB2mermaid

私は下記の順番でインストールしました。

# pip install SQLAlchemy

# pip install mysqlclient

# pip install DB2mermaid


DockerでMySQLを起動

サンプルデータの取得

DockerでMySQLを起動しデータを投入していきます。 データですが、DB2mermaidの公式を見るとどうやらSakilaを使っているようですので、そちらを利用します。

https://downloads.mysql.com/docs/sakila-db.tar.gz

上記をダウンロードし、db2mermaid/docker/mysql配下にsakila-schema.sqlとsakila-data.sqlとsakila.mwbを配置します。

docker
├── Dockerfile
├── docker-compose.yml
└── mysql
    ├── 00-sakila-schema.sql
    ├── 10-sakila-data.sql
    └── sakila.mwb

このとき、ファイル名は00-sakila-schema.sql、10-sakila-data.sqlに変えておきましょう。


Dokerfileの作成

dockerディレクトリ配下に、Dockerfileを作成します。

FROM --platform=linux/x86_64 mysql:5.7

COPY ./mysql/*.sql /docker-entrypoint-initdb.d/

FROM部分に--platform=linux/x86_64が入っていますが、M1Macで必要な記載になります。
WindowやIntel Mac系は要らないはずです。

下記記事が参考になるかもしれません。
M1Mac環境でDockerのMySQLを動かす - Qiita


docker-compose.ymlの作成

dockerディレクトリ配下に、docker-compose.ymlを作成します。

version: '3'

services:
  mysql:
    container_name: mysql_container
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: sakila
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      TZ: "Asia/Tokyo"
    restart: always

ここまでくると、下記のようなディレクトリ構成になっているはずです。

docker
├── Dockerfile
├── docker-compose.yml
└── mysql
    ├── 00-sakila-schema.sql
    ├── 10-sakila-data.sql
    └── sakila.mwb


MySQLを起動

dockerディレクトリ配下で、下記コマンドを実行します。 実行後は特にエラーが起きなければ、正常に起動できているはずです。

# docker compose up -d --build
# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                               NAMES
d2c54b60b1ac   docker_mysql   "docker-entrypoint.s…"   2 seconds ago   Up 2 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   mysql_container

DBeaverで接続確認

DBeaverを利用して実際にMySQLに接続できるか確認してみましょう。
DBeaverについて簡単に説明すると、マルチプラットフォームデータベースツールで、MySQLだけでなく、PostgreSQLSql ServerMariaDBなど様々なデータベースをサポートしています。
詳しい使い方などは、公式などを参考にしてください。


接続方法は下記の通りです。

① DBeaverを開く

② 接続を選択

MySQLを選択
色々ありますが、今回はMySQL(左上)を選択します。

④ 下記のように設定

Server host:127.0.0.1
port:3306
Databases::sakila
ユーザー名:root
パスワード:passowrd

パスワードですが、ユーザ名がrootになっているため、docker-compose.ymlで指定したMYSQL_ROOT_PASSWORDpasswordを入れます。


⑤ テスト接続
テスト接続を押下し、接続が確認できればOK

実際にSQLを叩いてみると接続できていることがわかります。



DB2mermaidを利用する

DB2mermaidを利用して、先ほどのMySQLのER図を作成してみましょう。

Pythonファイルの作成

DB2mermaidに記載のある通りに書けば動きますので、その通りにコードを書いていきます。
db2mermaidディレクトリ配下にmain.pyを作成します。

公式に書いてあるuserやdb_nameは適切なものに書き換えます。

# coding:utf-8

from db2mermaid.db2mermaid import DB2Mermaid

if __name__ == '__main__':
    dm = DB2Mermaid()
    dm.init_db("root", "password", "127.0.0.1", "3306", "sakila")
    dm.generate()

ここまでくると、下記のようなディレクトリ構成になっているかと思います。

db2mermaid
├── docker
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── mysql
│       ├── 00-sakila-schema.sql
│       ├── 10-sakila-data.sql
│       └── sakila.mwb
└── main.py


実行してER図を取得する

main.pyを実行します。

# python main.py

db_url:  mysql://root:password@127.0.0.1:3306/sakila
SAWarning: Did not recognize type 'geometry' of column 'location'
  self.meta.reflect(bind=engine)
table name🌟 actor
table name🌟 address
table name🌟 city
table name🌟 country
table name🌟 category
table name🌟 customer
table name🌟 store
table name🌟 staff
table name🌟 film
table name🌟 language
table name🌟 film_actor
table name🌟 film_category
table name🌟 film_text
table name🌟 inventory
table name🌟 payment
table name🌟 rental

実行が終わると、db2mermaidディレクトリ配下に下記のようなer.mdファイルが作成されます。

```mermaid
erDiagram
    actor{
        SMALLINT actor_id PK
        VARCHAR(45) first_name
        VARCHAR(45) last_name
        TIMESTAMP last_update
}
    address{
        SMALLINT address_id PK
        VARCHAR(50) address
        VARCHAR(50) address2
        VARCHAR(20) district
        SMALLINT city_id FK
        VARCHAR(10) postal_code
        VARCHAR(20) phone
        NULL location
        TIMESTAMP last_update
}
    city{
        SMALLINT city_id PK
        VARCHAR(50) city
        SMALLINT country_id FK
        TIMESTAMP last_update
}
    country{
        SMALLINT country_id PK
        VARCHAR(50) country
        TIMESTAMP last_update
}
    category{
        TINYINT category_id PK
        VARCHAR(25) name
        TIMESTAMP last_update
}
    customer{
        SMALLINT customer_id PK
        TINYINT store_id FK
        VARCHAR(45) first_name
        VARCHAR(45) last_name
        VARCHAR(50) email
        SMALLINT address_id FK
        TINYINT active
        DATETIME create_date
        TIMESTAMP last_update
}
    store{
        TINYINT store_id PK
        TINYINT manager_staff_id FK
        SMALLINT address_id FK
        TIMESTAMP last_update
}
    staff{
        TINYINT staff_id PK
        VARCHAR(45) first_name
        VARCHAR(45) last_name
        SMALLINT address_id FK
        BLOB picture
        VARCHAR(50) email
        TINYINT store_id FK
        TINYINT active
        VARCHAR(16) username
        VARCHAR(40) password
        TIMESTAMP last_update
}
    film{
        SMALLINT film_id PK
        VARCHAR(128) title
        TEXT description
        YEAR release_year
        TINYINT language_id FK
        TINYINT original_language_id FK
        TINYINT rental_duration
        DECIMAL(4_2) rental_rate
        SMALLINT length
        DECIMAL(5_2) replacement_cost
        ENUM rating
        SET special_features
        TIMESTAMP last_update
}
    language{
        TINYINT language_id PK
        CHAR(20) name
        TIMESTAMP last_update
}
    film_actor{
        SMALLINT actor_id PK
        SMALLINT film_id PK
        TIMESTAMP last_update
}
    film_category{
        SMALLINT film_id PK
        TINYINT category_id PK
        TIMESTAMP last_update
}
    film_text{
        SMALLINT film_id PK
        VARCHAR(255) title
        TEXT description
}
    inventory{
        MEDIUMINT inventory_id PK
        SMALLINT film_id FK
        TINYINT store_id FK
        TIMESTAMP last_update
}
    payment{
        SMALLINT payment_id PK
        SMALLINT customer_id FK
        TINYINT staff_id FK
        INTEGER rental_id FK
        DECIMAL(5_2) amount
        DATETIME payment_date
        TIMESTAMP last_update
}
    rental{
        INTEGER rental_id PK
        DATETIME rental_date
        MEDIUMINT inventory_id FK
        SMALLINT customer_id FK
        DATETIME return_date
        TINYINT staff_id FK
        TIMESTAMP last_update
}
```


作成されたER図を見る

作成されたer.mdからER図を可視化するには、オンラインエディタを使う場合とVScodeで見る方法など色々あります。

オンラインエディタの場合

オンラインエディタの場合、Mermaid Live Editorがあるので、そちらを利用します。

Online FlowChart & Diagrams Editor - Mermaid Live Editor

ただし、er.mdの中身をそのまま貼り付けるとエラーが出てしまいますので、er.mdファイルの上部にある```mermaidと下部にある```を削除して貼り付けましょう。

オンラインエディタ上では下記のようにしてみることが可能です。

VSCodeで見る場合

VSCodeで見る場合は、拡張機能Markdown Preview Mermaid Supportというものがあるので、それをインストールすればプレビュー機能(Macの場合:Cmd + k, v)から見ることが可能です。


まとめ

DB2mermaidを利用して、MySQLからER図を作成することができました。
ただ、今のところ対応しているのはMySQLのみで、また、テーブル間のリレーションも生成できないようです。
この辺りは将来的に対応してくれるのをゆっくり待ちましょう。( ̄∀ ̄)


その他:トラブルシューティングなど

mysqlclientインストール時のエラーについて

mysqlclientをインストールしようとすると、私の場合下記のエラーが出てきました。

Collecting mysqlclient
  Using cached mysqlclient-2.1.1.tar.gz (88 kB)
  Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error

  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [16 lines of output]
      /bin/sh: mysql_config: command not found
      /bin/sh: mariadb_config: command not found
      /bin/sh: mysql_config: command not found
      Traceback (most recent call last):
        File "<string>", line 2, in <module>
        File "<pip-setuptools-caller>", line 34, in <module>
        File "/private/var/folders/k7/x4m8rfmn2p1_xy7_24gdkvyc0000gn/T/pip-install-uc7mnp5y/mysqlclient_b7fe84c002c94e8ba150581772b02fdd/setup.py", line 15, in <module>
          metadata, options = get_config()
        File "/private/var/folders/k7/x4m8rfmn2p1_xy7_24gdkvyc0000gn/T/pip-install-uc7mnp5y/mysqlclient_b7fe84c002c94e8ba150581772b02fdd/setup_posix.py", line 70, in get_config
          libs = mysql_config("libs")
        File "/private/var/folders/k7/x4m8rfmn2p1_xy7_24gdkvyc0000gn/T/pip-install-uc7mnp5y/mysqlclient_b7fe84c002c94e8ba150581772b02fdd/setup_posix.py", line 31, in mysql_config
          raise OSError("{} not found".format(_mysql_config_path))
      OSError: mysql_config not found
      mysql_config --version
      mariadb_config --version
      mysql_config --libs
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.

上記の中にOSError: mysql_config not foundを見つけました。どうやらmysql_configがないらしい。

実際に探してみてもありませんでした。

# which mysql_config
mysql_config not found

そんなこんなで探していると下記記事が見つかりまして。
mysql_config not foundとでたときの対処法 - Qiita

こちらの記事に書いてあることを順に上からやっていきます。

# brew install mysql-connector-c

# echo 'export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH"' >> ~/.zshrc
# export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH"
# which mysql_config 
/opt/homebrew/opt/mysql-client/bin/mysql_config

# chmod 777 /opt/homebrew/opt/mysql-client/bin/mysql_config

で、最後にvimysql_configファイルを開いて編集するらしいのですが、私の場合は下記のようになっていたため、編集しなくてもいいと思い、今回は無視しました。

# vi /opt/homebrew/opt/mysql-client/bin/mysql_config

~省略~
libs="-L$pkglibdir"
libs="$libs -lmysqlclient -lz -L/opt/homebrew/lib -lzstd -L/opt/homebrew/opt/openssl@1.1/lib -lssl -lcrypto -lresolv"
~省略~

再度pip install mysqlclientすることで無事installすることができました。

ファイル名を変える意味

サンプルデータの取得部分でファイル名を、00-sakila-schema.sql、10-sakila-data.sqlに変更した意味ですが、Dockerが関係しています。 DockerのSQL系のイメージは、コンテナ内の特定の場所にファイルを配置すると、ファイル名を元に自動的にデータベースを作成してくれます。

このときの実行順ですが、Dockerではファイル名順に実行します。
つまり、sakila-schema.sqlとsakila-data.sqlのままだと、sakila-data.sqlが先に実行され、sakila-schema.sqlが後から実行されることになり、テーブルなどの定義がないままデータを投入しようとしてDBの作成に失敗してしまいます。

sakila-data.sql  # 1番目に実行
sakila-schema.sql # 2番目に実行


これを避けるため、ファイル名を00-sakila-schema.sql、10-sakila-data.sqlに変えたのでした。
MySQL系に限った話ではないですが、実行順には気をつけるようにしましょう。

参考記事

DB2mermaid · PyPI

mysql_config not foundとでたときの対処法 - Qiita

M1Mac環境でDockerのMySQLを動かす - Qiita

DBeaver Community | Free Universal Database Tool

Online FlowChart & Diagrams Editor - Mermaid Live Editor