Laravelでマイグレーションを実行する際にハマったのでメモ。

例として、注文データであるordersテーブルに対し、created_atの年単位でパーティションを作成したい場合。

実際のコード例

具体的なコード例は下記になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Schema::create('orders', function (Blueprint $table) {
    $table->unsignedBigInteger('id');
    $table->string('item_code');
    $table->integer('price');
    // some columns...

    $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
    $table->timestamp('updated_at', 0)->nullable();

    $table->primary(['id', 'created_at']);
});

Schema::table('orders', function (Blueprint $table) {
    $table->bigIncrements('id')->change();
});

DB::statement("ALTER TABLE `orders` PARTITION BY RANGE (unix_timestamp(created_at)) (
    PARTITION p2020 VALUES LESS THAN (unix_timestamp('2021-01-01 00:00:00')),
    PARTITION p2021 VALUES LESS THAN (unix_timestamp('2022-01-01 00:00:00')),
    PARTITION p2022 VALUES LESS THAN (unix_timestamp('2023-01-01 00:00:00')),
    PARTITION p2023 VALUES LESS THAN (unix_timestamp('2024-01-01 00:00:00')),
    PARTITION p2024 VALUES LESS THAN (unix_timestamp('2025-01-01 00:00:00')),
    PARTITION p2025 VALUES LESS THAN (unix_timestamp('2026-01-01 00:00:00')),
    PARTITION p2026 VALUES LESS THAN (unix_timestamp('2027-01-01 00:00:00')),
    PARTITION p2027 VALUES LESS THAN (unix_timestamp('2028-01-01 00:00:00')),
    PARTITION p2028 VALUES LESS THAN (unix_timestamp('2029-01-01 00:00:00')),
    PARTITION p2029 VALUES LESS THAN (unix_timestamp('2030-01-01 00:00:00')),
    PARTITION p2030 VALUES LESS THAN (unix_timestamp('2031-01-01 00:00:00')),
    PARTITION pmax VALUES LESS THAN (MAXVALUE)
)");

ポイントとしては下記です。

  • Schema::create()でauto incrementなカラムを作成するとCREATE文でprimary keyになってしまうため、通常のintegerカラムを作成したあとでprimary keyを設定する必要がある
  • パーティションを貼るためにcreated_atカラムにデフォルト値が必要
  • パーティション作成自体は該当メソッドが無いのでDB::statement()を使う必要がる

テーブルの確認

作成されたテーブルを show create table orders; のSQLを流して確認すると次のような内容となります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TABLE `orders` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `item_code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `price` int(11) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`,`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
 PARTITION BY RANGE (unix_timestamp(`created_at`))
(PARTITION `p2020` VALUES LESS THAN (1609426800) ENGINE = InnoDB,
 PARTITION `p2021` VALUES LESS THAN (1640962800) ENGINE = InnoDB,
 PARTITION `p2022` VALUES LESS THAN (1672498800) ENGINE = InnoDB,
 PARTITION `p2023` VALUES LESS THAN (1704034800) ENGINE = InnoDB,
 PARTITION `p2024` VALUES LESS THAN (1735657200) ENGINE = InnoDB,
 PARTITION `p2025` VALUES LESS THAN (1767193200) ENGINE = InnoDB,
 PARTITION `p2026` VALUES LESS THAN (1798729200) ENGINE = InnoDB,
 PARTITION `p2027` VALUES LESS THAN (1830265200) ENGINE = InnoDB,
 PARTITION `p2028` VALUES LESS THAN (1861887600) ENGINE = InnoDB,
 PARTITION `p2029` VALUES LESS THAN (1893423600) ENGINE = InnoDB,
 PARTITION `p2030` VALUES LESS THAN (1924959600) ENGINE = InnoDB,
 PARTITION `pmax` VALUES LESS THAN MAXVALUE ENGINE = InnoDB)