MySQL
CakePHP3のMigrationsでDB接続先を切り替える方法
CakePHP3 の Migrations コマンドを使ってマイグレーションする際、DB 接続先を明示的に指定することが出来ます。
この記事の内容は、以下のように CakePHP の設定ファイルに複数の Datasource が設定されていることが前提になります。
config/app.php:
/** * Connection information used by the ORM to connect * to your application's datastores. * Do not use periods in database name - it may lead to error. * See https://github.com/cakephp/cakephp/issues/6471 for details. * Drivers include Mysql Postgres Sqlite Sqlserver * See vendor\cakephp\cakephp\src\Database\Driver for complete list */ 'Datasources' => [ 'default' => [ // 省略 ], 'my_other_connection' => [ // 省略 ] ],
Datasource を指定するオプション
例えば config/app.php
で設定した my_other_connection
の Datasource に接続する場合、以下のように -c オプションにデータソース名を指定します。
./bin/cake migrations migrate -c my_other_connection
また、以下のように接続先を指定しないとデフォルトの Datasource が使用されます。
./bin/cake migrations migrate
ただし、この方法は全てのマイグレーションファイルで指定した接続先が使用されます。マイグレーションファイルごとに接続先を切り替えたい場合は以下を参照してください。
マイグレーションファイルごとに接続先を切り替える方法
少しアナログな方法にはなりますが、少し手を加えることで実現できます。
まず、以下のように接続先ごとにフォルダを分けて、その中にマイグレーションファイルを入れておきます。
- config/Migrations/default (
default
コネクション用フォルダ) - config/Migrations/other (
my_other_connection
コネクション用フォルダ)
この状態でマイグレーションをするときに -s (–source=SOURCE) オプションで上記のディレクトリを指定してマイグレーションします。
./bin/cake migrations migrate -c default -s Migrations/default ./bin/cake migrations migrate -c my_other_connection -s Migrations/other
マイグレーションの実行履歴はコネクションごとの phinxlog テーブル上で管理されるため、バッティングせずにマイグレーション出来ます。
コマンドオプション指定の組み合わせは間違えないよう注意する必要があります。
MySQLの複合主キーテーブル検索時の速度比較
MySQL の複合主キーテーブルのレコードを何件かピックアップして主キー検索したい機会があったので、いくつかのパターンの SQL で検索してパフォーマンス比較をしてみました。
実験の内容
- それぞれ適当にピックアップした15レコードを1クエリで検索する
- 実行時間は同じクエリを5回実行したときの最小と最大の時間を計測
- レコードは適当に100,000件投入
実験環境
- Ubuntu 13.10 (on Vagrant)
- MySQL 5.5.37
- InnoDB
使用したテーブル
CREATE TABLE `myTable` ( `player_id` int(11) NOT NULL, `id` int(11) NOT NULL, `body` varchar(255) DEFAULT NULL, PRIMARY KEY (`player_id`,`id`) ) ENGINE=InnoDB;
各検索方法の実行時間とインデックス使用状況
1. OR検索の場合
SQL例
SELECT * FROM `myTable` WHERE (`player_id` = 50 AND `id` = 4856) OR (`player_id` = 61 AND `id` = 4274);
※実験時は15個のORを繋げて検索しましたが長くなるのでここでは省略しています。
実行時間
1.2ms ~ 1.5ms
EXPLAIN結果
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | myTable | range | PRIMARY | PRIMARY | 8 | NULL | 15 | Using where |
2. UNION ALL検索の場合
SQL例
SELECT * FROM `myTable` WHERE (`player_id` = 50 AND `id` = 4856) UNION ALL SELECT * FROM `myTable` WHERE (`player_id` = 61 AND `id` = 4274);
実行時間
1.5ms ~ 2.0ms
EXPLAIN結果
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | PRIMARY | myTable | const | PRIMARY | PRIMARY | 8 | const,const | 1 | |
2 | UNION | myTable | const | PRIMARY | PRIMARY | 8 | const,const | 1 | |
… | … | … | … | … | … | … | … | … | … |
15 | UNION | myTable | const | PRIMARY | PRIMARY | 8 | const,const | 1 | |
NULL | UNION RESULT | ALL | NULL | NULL | NULL | NULL | NULL |
3. WHERE IN の複合カラム指定による検索の場合
SQL例
SELECT * FROM `myTable` WHERE (player_id, id) IN ((50, 4856),(61, 4274));
実行時間
40.9ms ~ 49.7ms
EXPLAIN結果
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | myTable | ALL | NULL | NULL | NULL | NULL | 100714 | Using where |
コメント
最も高速なのは普通に OR で繋げる検索でした。range スキャンになるんですね。次点で UNION ALL 検索。ちなみに ALL 無しの UNION に変えてもほぼ同じ速度でした。
そして最も遅かったのは WHERE IN 検索でした。IN 句に指定する件数が多いとオプティマイザはフルスキャンを選択するため大幅に遅い結果になりました。