このページはCalíope 1.7を紹介しています。私がいま作っているバージョンです。1.6は、Mac、iPad、iPhone、Apple Watch、Apple TV、Apple Vision Pro向けにApp Storeで公開中です。それぞれの機能がどのバージョンで入ったかは変更履歴に書いてあります。

すべてのトピックに「Calíopeで開く」ボタンを追加します。アプリがインストールされている場合にのみ機能します。

データ移行

サーバ間でオブジェクトを移行

テーブル、ビュー、ルーチン、トリガー、イベントを別のサーバへ、または同じサーバの別のデータベースへコピーします。

場所: ワークスペース › ツール › データ移行

ワークスペースのサイドバーから「データ移行」を開きます。この接続のテーブル、ビュー、ルーチン、トリガー、イベントを、別のサーバへ、または同じサーバの別のデータベースへコピーします。

コピーするものを選びます。選ぶのは左側のツリーです。その見出しには名前で絞り込むフィールドがあり、データベース名やオブジェクト名の一部を入力すると、データベースを1つずつ展開しなくても一覧を絞り込めます。オブジェクトは種類(テーブル、ビュー、ルーチン、トリガー、イベント)ごとにまとめられ、オブジェクトをクリックするとチェックが付きます。各データベースのチェックボックスはその下のすべてを選択または解除し、横には全体のうち選択したオブジェクトの数が表示されます。「消去」で選択を空にします。Calíopeは順序をテーブル、ビュー、ルーチン、トリガー、イベントに固定するので、各オブジェクトは依存するものがすでに作成された状態で作られます。

行き先を選びます。「移行先:」の横で「移行先のサーバを選択」を開き、「接続マネージャ」に保存されている接続を1つ選んで「接続」をクリックします。「移行先のデータベース」には、オブジェクトを入れるデータベースを入力します。空欄のままにすると、各オブジェクトは移行元と同じデータベースに入ります。そのデータベースがなければCalíopeが作成し、ビューの参照もそこから読むように書き換えます。

オプション:「移行先で置き換える」は、何かを作成する前に選択したものをすべて削除します。テーブルに依存するものを先に、子テーブルを親テーブルより先に削除するので、同じ移行をもう一度実行しても安全です。「データを書き出す」は各テーブルの行をコピーします。「外部キーのチェックを省略」は各オブジェクトを読み込む間だけ外部キーのチェックを無効にするので、テーブルはどの順序で届いてもかまいません。

「移行」をクリックします。ログにはオブジェクトごとに1行が出て、移行先のデータベースと、テーブルならコピーした行数が表示されます。「停止」は、あるオブジェクトと次のオブジェクトの間で止めます。

コピーしたテーブルの外部キーは、すべてのテーブルが行とともにそろった最後に作成されます。テーブルが届く順序はもう関係ありません。

エンジンファミリーが異なる場合は、何かを実行する前に「移行」の横の通知がそのことを伝えます。一方のエンジンのDDLはもう一方には理解されないため、何も作成されません。コピーされるのは行だけで、移行先にすでにある同じ名前のテーブルに、列を名前で対応付けて入れます。移行先にないテーブルや、テーブルではないオブジェクトはスキップされ、ログにその旨が出ます。

同じファミリーの中ではDDLがそのまま移りますが、ある製品にあるものが別の製品にはないことがあります。何かを作成する前に、移行先が受け入れられないチェック済みのオブジェクト(移行先にないトリガー、ルーチン、イベントや、移行先にない列の型を持つテーブル)をログに示してスキップし、「移行先で置き換える」の対象からも外します。また、移行先が作成しない種類のインデックスを持たずに届くテーブルも示します。

TiDB

MySQLやMariaDBからの場合、TiDBにはトリガー、ルーチン、イベントがないためこれらは移らず、空間列(POINT、GEOMETRY…)を持つテーブルも移りません。FULLTEXTインデックスは作成されません。AUTO_RANDOM列は値を保ちます。Calíopeはコピーの間、移行先のセッションでallow_auto_random_explicit_insertをオンにします。

SQL Server

IDENTITY列は値を保ちます(Calíopeはコピーの間IDENTITY_INSERTをオンにします)が、カウンタは保ちません。移行先では、次の行はコピーされた最大値の続きから始まります。各オブジェクトは自分のスキーマに入り、そのスキーマがなければ作成されます。「移行先のデータベース」にデータベース名だけを指定すると、各オブジェクトはスキーマを保ちます。demo.dboはcopia.dboへ、demo.rrhhはcopia.rrhhへ移ります。

PostgreSQL

ここではデータベースは接続中のデータベースのスキーマです。「移行先のデータベース」はオブジェクトの行き先のスキーマを指定し、なければ作成されます。コピーするテーブルが使う型(ENUMやドメイン)が先に作成されます。移行先にすでにある型はそのまま残します。作り直すには、それを使う列をすべて削除しなければならないからです。コピーした関数のsearch_pathは移行先のスキーマを指すので、そのトリガーは移行元ではなく移行先に書き込みます。

ClickHouse

各テーブルは、サーバが保持しているDDL(エンジン、PARTITION BY、ORDER BY、TTL、SETTINGSを含む)から作成されます。外部キーはなく、「外部キーのチェックを省略」もありません。行は100行ずつのINSERT文で入り、Array、Map、Tupleの列は型を保って届きます。マテリアライズドビューはテーブルの後に作成され、空の状態で始まります。受け取るのは、それ以降に挿入されるものだけです。TOで別のテーブルに書き込むビューなら、その行も持っていくためにそのテーブルにもチェックを付けてください。

移行先が移行元と同じサーバで、オブジェクトが自分自身のデータベースに入ることになる場合、「移行」は無効のままになり、警告がその理由を示します。「移行先で置き換える」がオンだと、コピーが行を読む前に元のオブジェクトを削除してしまうからです。

必要なサーバがセレクタに表示されない場合は、先に「接続マネージャ」で追加してから、データ移行を開き直してください。

Oracle

移行先がOracleの場合、「外部キーのチェックを省略」はありません。Oracleはセッション単位で外部キーを無効にしないからです。2つのOracleスキーマの間では、存在しない移行先スキーマはパスワードなしのユーザ(NO AUTHENTICATION)として、その表領域へのクォータ付きで作成されます。テーブルはOracleのDDLで届き、行は実行しながら確定する複数行のINSERTで、日付はTIMESTAMPリテラルで、外部キーは最後に届きます。Oracleは名前を大文字で保存します。ファミリーをまたぐ場合、テーブルとその列は大文字と小文字だけが違うもの(CLIENTESとclientes)とも対応付けられます。

環境タグがある場合:移行先はそのプロファイルのタグで保護されます。タグが書き込みの確認を求めるなら、移行は開始前にオブジェクト数を示して一度だけ確認し、プレビューでは確認しません。読み出し専用なら、移行先には何も書き込みません。このタブの接続に読み出し専用のタグがある場合、このツールは表示されません。

キーワード: 移行、データ移行、コピー、移動、移行先のサーバ、移行先の接続、セレクタ

移行SQLのプレビュー

移行する前に、実行されるSQLを確認します。

場所: データ移行 › プレビュー

「プレビュー」にチェックを付けると、ボタンが「SQLを生成」に変わります。Calíopeは何も実行せず、移行で実行されるSQLを出力パネルに書き出すので、確認したりコピーしたりできます。これは移行が実行するのと同じスクリプトです。CREATE DATABASE IF NOT EXISTS、そのデータベースへの切り替え、「外部キーのチェックを省略」がオンなら外部キーのチェックの無効化、「移行先で置き換える」がオンなら選択したもの全部のDROP(テーブルに依存するものを先に、続いて子テーブルを親テーブルより先に)、それから各オブジェクト、「データを書き出す」がオンならINSERT文が並びます。ルーチンとトリガーはDELIMITER //とDELIMITER ;の間に入るので、スクリプトはSQLエディタの「スクリプトを実行」でもそのまま実行できます。プレビューモードでは移行先の接続は必要ありません。

外部キーは最後、すべてのテーブルとその行の後に入ります。

移行先に接続している場合、スクリプトの冒頭には、移行先が受け入れられないため含まれないものがコメントで示されます。

TiDB

TiDBでは、移行と同じように、スクリプトはINSERTの前にallow_auto_random_explicit_insertをオンにし、最後にオフにします。

SQL Server

SQL Serverでは、スクリプトはデータベースとスキーマがなければ作成し(IF DB_ID(…) IS NULL)、DELIMITERはありません(各ルーチンはそれぞれのEXECに入ります)。ID値を持つ行はSET IDENTITY_INSERT … ONとOFFの間に入ります。

PostgreSQL

PostgreSQLでは、スクリプトはスキーマがなければ作成し(CREATE SCHEMA IF NOT EXISTS)、SET session_replication_roleで外部キーのチェックを無効にし、テーブルが使う型をテーブルより先に作成します。DELIMITERはなく、関数の本体は$function$の引用符の間に入ります。

ClickHouse

ClickHouseでは、スクリプトはデータベースを切り替えません(各オブジェクトが自分のデータベースを前に付けます)。外部キーがないので無効にもせず、すべてのDROPにSYNCが付きます。Array、Map、Tupleの列は、INSERTの中でJSONExtract('…', 'type')として入ります。

Oracle

Oracleでは、スクリプトにUSEはありません。各オブジェクトがスキーマを前に付け、存在しない移行先スキーマを作成するPL/SQLブロックから始まります。外部キーは無効にせず、最後に回します。

キーワード: プレビュー、SQLプレビュー、実行前に確認

データベースのスキーマを比較

同じサーバ上の2つのデータベースを比較し(テーブル、ビュー、ルーチン、トリガー、イベント)、移行スクリプトを生成します。

場所: ワークスペース › ツール › スキーマ比較

「スキーマ比較」ツールは、同じサーバ上の2つのデータベースを分析し、テーブル、ビュー、プロシージャ、関数、トリガーにわたって何が変わったかを正確に表示します。

MySQLMariaDBAurora

MySQLとMariaDBではイベントも比較します。

TiDB

TiDBでは、テーブル、ビュー、シーケンスを比較します。TiDBにはプロシージャ、関数、トリガー、イベントがありません。

SQL Server

SQL Serverでは、それぞれの側がデータベースのスキーマ(demo.dbo)で、2つは同じサーバの別々のデータベースにあってもかまいません。

PostgreSQL

PostgreSQLでは、それぞれの側が接続中のデータベースのスキーマ(demo、ventas)です。

Oracle

Oracleでは、それぞれの側が接続先データベースのスキーマ(DEMOやDEMO_R1のようなユーザ)で、パッケージ、型、シーケンスも比較します。

スキーマ比較を開くには:
サイドバーで「スキーマ比較」(向かい合う矢印のアイコン)をクリックします。新しいタブで開きます。

基本的な使い方:
1. 上部のバーで「比較元」と「比較先」を選びます。スクリプトは比較元を、比較先と一致するまで変更します。比較先にしかないものは比較元に作成され、比較元にしかないものは削除されます。
2. 「比較」をクリックします。Calíopeは各オブジェクトの定義を、サーバ自身が書くとおりに両側で読み込みます。
3. 「変更のみ」をオンにすると、一致するものが隠れます。
4. レポートはオブジェクトの種類ごとにまとめられています。どの行も展開できます。変更されたテーブルは、変更ごとに今の定義と変更後の定義を表示し、変更されたビューやルーチンは2つの完全な定義を並べて表示し、新規や削除のオブジェクトはそのDDLを表示します。
5. スクリプト全体なら「SQLをコピー」を、そのオブジェクトだけなら行のコピーボタンをクリックします。
6. 「SQLエディタ」で「スクリプトを実行」を使って実行します。「セーフモード」がオンなら、スクリプトはサーバに届く前に止まります。そのあともう一度比較すると、両側は同一になるはずです。

MySQLMariaDBAurora

定義は各オブジェクトのSHOW CREATE …で、エディタは、ルーチンとトリガーを包むDELIMITERブロックを理解します。

TiDB

TiDBでは、定義は各オブジェクトのSHOW CREATE …で、TiDB独自のコメント(/*T![clustered_index] CLUSTERED */)は届いたまま残ります。スクリプトに含まれ、サーバがそれを読みます。

SQL Server

定義はカタログから取ります(ビュー、ルーチン、トリガーはsys.sql_modules)。T-SQLはそれらがバッチの中で単独であることを求めるので、ビュー、ルーチン、トリガーはそれぞれ独自のEXEC … sp_executesqlに入り、スクリプトはGO行なしで実行できます。

PostgreSQL

定義は、サーバがpg_get_viewdef、pg_get_functiondef、pg_get_triggerdefで書くものです。

Oracle

定義は、サーバがDBMS_METADATA.GET_DDLで書くもので、ストレージや表領域は含みません。比較の前に、出荷時の値を取り除きます。各制約のENABLEと、アイデンティティやシーケンスのデフォルトのオプションです。

テーブルについて生成するもの:

MySQLMariaDBAuroraTiDB

- 比較元にないものには、列、インデックス、オプションを含む完全なCREATE TABLE IF NOT EXISTS。
- 余分なものにはDROP TABLE IF EXISTS。
- ADD/DROP/MODIFY COLUMNを使うALTER TABLE。型、NULL許容、デフォルト値、コメント、文字セット、生成列の式を保ちます。
- 主キー、インデックス、CHECK制約の追加と削除、さらにテーブルオプションの変更(ENGINE、DEFAULT CHARSET、COLLATE、ROW_FORMAT、COMMENT)。

SQL Server

- 比較元にないものには、列、キー、制約を含むIF OBJECT_ID(…) IS NULL CREATE TABLEと、インデックスごとのCREATE INDEX。
- 余分なものにはDROP TABLE IF EXISTS。
- ADD、ALTER COLUMN、DROP COLUMNを使うALTER TABLE。列を削除する前に、スクリプトはその列にかかっているデフォルト制約を削除します。
- 主キー、インデックス、CHECK制約の追加と削除。

PostgreSQL

- 比較元にないものには、列と制約を含むCREATE TABLE IF NOT EXISTSと、インデックスごとのCREATE INDEX。
- 余分なものにはDROP TABLE IF EXISTS。
- ADD COLUMN、DROP COLUMN、ALTER COLUMN … TYPE、SET/DROP NOT NULL、SET/DROP DEFAULTを使うALTER TABLE。
- 主キー、インデックス、CHECK制約の追加と削除、テーブルのコメント(COMMENT ON TABLE)。

Oracle

- 比較元にないものには、列、主キー、UNIQUEとCHECKの制約、パーティション分割を含むCREATE TABLE IF NOT EXISTSと、インデックスごとのCREATE INDEX。空間インデックスの前にはそのメタデータ(USER_SDO_GEOM_METADATA)が置かれます。これがないと、サーバはインデックスを作成しません。
- 余分なものにはDROP TABLE IF EXISTS … CASCADE CONSTRAINTS PURGE。
- ADD、DROP COLUMN、MODIFYを使うALTER TABLE。変わるもの(型、デフォルト値、NULL許容)だけを書きます。
- 主キー、インデックス、制約の追加と削除、テーブルとその列のコメント(COMMENT ON)。

それ以外について生成するもの:
ビューやルーチンは部分的には修正できません。定義が違えば、スクリプトは比較先からそれを作り直し、比較元のスキーマへの参照を書き換えて、正しい場所を指すようにします。

MySQLMariaDBAuroraTiDB

DROP + CREATEで作り直します。

SQL Server

ビュー、プロシージャ、関数、トリガーのどれもが受け付けるCREATE OR ALTERで作り直します。

PostgreSQL

CREATE OR REPLACEで作り直します。それを持たないトリガーとマテリアライズドビューは、削除してから作成し直します。

Oracle

DDLがすでに持っているCREATE OR REPLACEで作り直します。それを持たないシーケンスとマテリアライズドビューは、削除してから作成し直します。トリガーは、修復するスキーマのテーブルに作成されます。

スクリプトの順序:
まずテーブル、次に外部キーを独自のブロックで(複数のテーブルを作成するとき、アルファベット順では依存関係が守られないからです)、そのあと残りのオブジェクトを種類ごとに、それぞれ依存関係の順で出力します。別のビューの上に作ったビューは、そのビューのあとに出力されます。

MySQLMariaDBAuroraSQL ServerTiDB

テーブルではない最初のオブジェクトの前に、スクリプトはUSEで使用中のデータベースを設定します。

PostgreSQL

テーブルの前に、そのスキーマ独自の型が来ます。列はそれで宣言されているからです。

Oracle

OracleにはUSEがありません。どの文も、修復するスキーマで修飾されます。テーブルの前に、列の宣言に使われているオブジェクト型(CREATE TYPE)が来ます。

意図的に無視するもの:

MySQLMariaDBAuroraTiDB

AUTO_INCREMENTのカウンタ。挿入のたびに進み、2つのコピーの間で一致することはありません。

TiDB

TiDBのAUTO_RANDOM_BASEも無視します。AUTO_RANDOMキーの同じカウンタです。

SQL ServerPostgreSQLOracle

アイデンティティ列の現在の値。挿入のたびに進み、2つのコピーの間で一致することはありません。

Oracle

シーケンスの現在の値(START WITH)も無視します。

扱わないもの:
既存のテーブルの列は並べ替えません。名前を変えた列は、削除と追加として読まれます。ビュー、ルーチン、トリガーはテキストとして比較するので、書式が変わっただけでも差分になります。

MySQLMariaDBAurora

パーティション分割の変更は検出して警告として記しますが、SQLにはしません。パーティションを分割し直すとテーブル全体が書き直されるからです。DEFINERの変更も差分になり、MariaDBでは、トリガーのDDLは書かれたときのテキストそのままです。開始時刻の違うイベントも差分になります。その時刻は定義の一部だからです。

TiDB

TiDBでも、パーティション分割の変更は検出して警告として記しますが、SQLにはしません。ビューのDEFINERの変更も差分になります。

PostgreSQL

独自の型(ENUM、ドメイン、複合型)は、ビューと同じように、独自の「型」グループで比較します。スクリプトは足りない型をそれを使うテーブルの前に作成し、比較元にしかない型を最後に削除します。末尾にラベルが増えただけのENUMはALTER TYPE … ADD VALUEで更新します。型のそれ以外の変更は、手作業で行うメモとしてスクリプトに残ります。使用中の型を作り直すと、それを使うすべての列を書き直すことになるからです。拡張機能が作成する型(PostGISのものなど)は除外します。そのCREATE EXTENSIONが持ってくるからです。

Oracle

違いのある使用中のオブジェクト型とパーティション分割の変更は、手作業で行うメモとしてスクリプトに残ります。既存の列にアイデンティティを加えることも同じで、サーバが許しません。システム名の制約(SYS_C…)は、その定義で照合します。

本番環境で実行する前に、必ずスクリプトを確認してください。

典型的な使い方:
デプロイの前に、本番環境(比較元)を開発用のスキーマ(比較先)と比べます。スクリプトは、手で書かなくても、本番環境を開発環境がすでに持っている状態にそろえます。

macOS、iPad、iPhone、Apple Vision Proで使えます。

ClickHouse

ClickHouseでは、テーブルとビューをそのSHOW CREATEから比較します。列、スキップインデックス、プロジェクション、制約、TTL、SETTINGS、コメントはALTER TABLEで同期します。エンジン、ORDER BY、PARTITION BY、PRIMARY KEY、SAMPLE BYの変更はALTERに収まらないので、テーブルを作り直す必要があるというコメントとしてスクリプトに出ます。マテリアライズドビューとディクショナリは比較せず、エンジンにはプロシージャもトリガーもありません。

キーワード: スキーマ比較、比較、スキーマ、ALTER TABLE、移行、差分、ADD COLUMN、DROP COLUMN、MODIFY COLUMN、SHOW CREATE TABLE、CREATE TABLE、インデックス、外部キー、パーティション分割、変更のみ