MySQLのテーブルローテーションなど

[ここ](http://hmatsu47.hatenablog.com/entry/2016/08/18/225422)にも書きましたが、近々社内の障害対応訓練があります。
訓練で使う（かもしれない）ネタをあげておかないとブーイングが出そうなので、非常にありがちな内容ですが、ここにあげておきます。
# テーブル定義を見る
まずはDESC。使うテーブルは[前にあげたネタで使ったやつ](http://qiita.com/hmatsu47/items/2d44c173a9114fd06853)です。

```mysql:
mysql> USE cardi_test;
Database changed

mysql> DESC test_data;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint(20)  | NO   | PRI | NULL    |       |
| name  | varchar(40) | NO   |     | NULL    |       |
| flag  | int(1)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql>
```
とりあえず構造はわかりますが、INDEXがわかりづらいので、CREATE文の内容を見てみます。

```mysql:
mysql> SHOW CREATE TABLE test_data\G
*************************** 1. row ***************************
       Table: test_data
Create Table: CREATE TABLE `test_data` (
  `id` bigint(20) NOT NULL,
  `name` varchar(40) NOT NULL,
  `flag` int(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_flag` (`flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
```
この例にはありませんが、パーティショニングの定義は、ただのDESCだけではわからないので要注意です。

ちなみに、今まで何気なく使っていたので全然気付いていませんでしたが、[DESC（DESCRIBE）文はEXPLAIN文のシノニム](https://dev.mysql.com/doc/refman/5.6/ja/describe.html)だそうです。

```mysql:
mysql> EXPLAIN test_data;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint(20)  | NO   | PRI | NULL    |       |
| name  | varchar(40) | NO   |     | NULL    |       |
| flag  | int(1)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> DESC SELECT * FROM test_data;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | test_data | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql>
```

# テーブルをコピーする
作業ミスに備えて、バックアップのためにテーブルをコピーすることがあると思いますが、うっかりするとINDEXやパーティショニングの定義が抜け落ちてしまいます。

```mysql:
mysql> CREATE TABLE test_data2 AS SELECT * FROM test_data;
Query OK, 10000 rows affected (0.43 sec)
Records: 10000  Duplicates: 0  Warnings: 0

mysql> DESC test_data2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint(20)  | NO   |     | NULL    |       |
| name  | varchar(40) | NO   |     | NULL    |       |
| flag  | int(1)      | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> SHOW CREATE TABLE test_data2\G
*************************** 1. row ***************************
       Table: test_data2
Create Table: CREATE TABLE `test_data2` (
  `id` bigint(20) NOT NULL,
  `name` varchar(40) NOT NULL,
  `flag` int(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
```
セカンダリINDEXどころか、PRIMARY KEYすらありませんね。
というわけで、こちらを使いましょう。

```mysql:
mysql> CREATE TABLE test_data3 LIKE test_data;
Query OK, 0 rows affected (0.02 sec)

mysql> DESC test_data3;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint(20)  | NO   | PRI | NULL    |       |
| name  | varchar(40) | NO   |     | NULL    |       |
| flag  | int(1)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> SHOW CREATE TABLE test_data3\G
*************************** 1. row ***************************
       Table: test_data3
Create Table: CREATE TABLE `test_data3` (
  `id` bigint(20) NOT NULL,
  `name` varchar(40) NOT NULL,
  `flag` int(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_flag` (`flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
```
INDEXも正しくコピーされました。

# テーブルをローテーションする
先の例の「CREATE TABLE … LIKE」構文は、当然ですが単独でも使えますので、テーブル構造だけコピーして空のテーブルを作り、レコードが入ったテーブルを別名に変更することで、テーブルローテーションをすることもできます。

```mysql:
mysql> CREATE TABLE test_data_new LIKE test_data;
Query OK, 0 rows affected (0.02 sec)

mysql> RENAME TABLE test_data TO test_data_old, test_data_new TO test_data;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT COUNT(*) FROM test_data;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> SELECT COUNT(*) FROM test_data_old;
+----------+
| COUNT(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.00 sec)

mysql> DESC test_data;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint(20)  | NO   | PRI | NULL    |       |
| name  | varchar(40) | NO   |     | NULL    |       |
| flag  | int(1)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> SHOW CREATE TABLE test_data\G
*************************** 1. row ***************************
       Table: test_data
Create Table: CREATE TABLE `test_data` (
  `id` bigint(20) NOT NULL,
  `name` varchar(40) NOT NULL,
  `flag` int(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_flag` (`flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
```
ローテーションに合わせてテーブル構造を変えたいときなどは、「CREATE TABLE … LIKE」構文を使わずに新しいCREATE文を発行したくなりますが、INDEXやパーティション定義などをうっかり忘れてしまいがちです。
「CREATE TABLE … LIKE」構文に続けてALTER文を発行する方法でミスを防ぐこともできますので（空のTABLEに対してのALTERは瞬時に終わります）、検討してみてください。