💡
スプレッドシートで管理していたテーブルコメントをDDLに反映する仕組みを作った
はじめに
既存システムのテーブル定義は、スプレッドシートで管理されていました。
カラムの意味や補足などの情報はスプレッドシート側にしか存在せず、
DBのDDLにはコメントがほとんど付いていない状態でした。
そのため、
- カラムの意味を確認するたびにスプレッドシートを見に行く必要がある
- DDLと定義書の二重管理になっている
- コメントの整備や更新が大変
といった課題がありました。
そこで、スプレッドシートにあるコメント情報を元に、
DDLへCOMMENTを反映する仕組みを作りました。
やりたかったこと
- スプレッドシートからコメントを取得
- 既存のDDLと比較
- ALTER TABLEでコメントを付与
全体の流れ
- 既存のDDLを取得
- スプレッドシートからコメントを取得
- 差分をもとにALTER文を生成
- SQLとして出力
既存DDLの取得
DDLはmysqldumpを使って取得しました。
mysqldump --no-data --skip-comments --compact \
-u user -p --host=127.0.0.1 --port=3306 db_name \
| grep -vE '^(CREATE TABLE|DROP TABLE).*20[0-9]{2}' > create_tables.sql
ログテーブル(YYYYMM系)を除外するため、grepでフィルタしています。
実行時に以下のような警告が出たため、
- --set-gtid-purged=OFF
- --single-transaction
を追加しました。
mysqldump --no-data --skip-comments --compact --set-gtid-purged=OFF --single-transaction \
-u user -p --host=127.0.0.1 --port=3306 db_name \
| grep -vE '^(CREATE TABLE|DROP TABLE).*20[0-9]{2}' > create_tables.sql
スプレッドシートからのデータ取得
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = [
"https://spreadsheets.google.com/feeds",
"https://www.googleapis.com/auth/spreadsheets"
]
credentials = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
client = gspread.authorize(credentials)
spreadsheet = client.open("テーブル定義")
worksheet = spreadsheet.worksheet("シート1")
data = worksheet.get_all_records()
ALTER文の自動生成
def generate_alter_table_sql(table_name, column_name, data_type, is_not_null, default_value, comment):
sql = f"ALTER TABLE {table_name} MODIFY COLUMN {column_name} {data_type}"
if is_not_null:
sql += " NOT NULL"
if default_value and default_value != "NULL":
sql += f" DEFAULT {default_value}"
if comment:
sql += f" COMMENT '{comment}'"
sql += ";"
return sql
実装上のポイント
既存定義を壊さない
MODIFY COLUMNは定義をすべて書く必要があるため、
既存DDLから情報を取得してそのまま使うようにしました。
YYYYMMテーブルの扱い
import re
re.sub(r"YYYYMM", target_date, table_name)
ハマったポイント
Google Sheets API のレート制限
Quota exceeded for quota metric 'Read requests'
対応
ディレイ
import time
time.sleep(1.5)
リトライ
from tenacity import retry, stop_after_attempt, wait_fixed
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
def get_data():
pass
結果
| Before | After |
|---|---|
| コメントはスプシにしかない | DDLにもコメントが付く |
| 定義確認のたびにスプシを見る | DBだけで意味が分かる |
| 手作業 | 自動生成 |
おわりに
大きな変更ではないですが、
スプレッドシート依存を減らす第一歩になりました。
Discussion