MySQL列挙型のテスト例

MySQL列挙型のテスト例

プロジェクトを開発しているとき、支払い済み、支払済み、クローズ済み、返金済みなどの注文ステータスなどのステータス フィールドに遭遇することがよくあります。以前のプロジェクトでは、これらのステータスは数値としてデータベースに保存され、次に定数を使用して PHP コードでマッピング テーブルが維持されていました。次に例を示します。

定数STATUS_PENDING = 0;
定数STATUS_PAID = 1;
定数STATUS_CLOSED = 2;
定数STATUS_REFUNDED = 3;

しかし、実際に使用してみると、それほど使いやすいものではないことがわかりました。さまざまな理由(バグの追跡、一時的な統計ニーズなど)により、MySQL サーバーにログインして、いくつかの SQL クエリを手動で実行する必要があることがよくあります。多くのテーブルにはステータス フィールドがあるため、SQL を記述するときに、PHP コード内のマッピング関係を参照する必要があります。注意しないと、異なるテーブルのステータス番号を混同し、大きな問題が発生する可能性があります。

そこで、新しいプロジェクトでさまざまな状態を保存するために、MySQL の enum 型を使用することにしました。使用中に、Laravel 移行ファイルで enum 型を使用してテーブルに変更を加えると (enum 型以外のフィールドを変更した場合でも)、エラーが報告されることがわかりました。

[Doctrine\DBAL\DBALException]
不明なデータベース タイプ列挙が要求されました。Doctrine\DBAL\Platforms\MySQL57Platform ではサポートされていない可能性があります。

検索した結果、doctrine は MySQL enum をサポートしていないことがわかりました。記事には enum の 3 つの欠点が挙げられています。

新しい列挙値を追加する場合は、テーブル全体を再構築する必要があり、データ量が多い場合は数時間かかることがあります。

列挙値のソート規則は、リテラル値のサイズではなく、テーブル構造の作成時に指定された順序に基づきます。

列挙値の検証に MySQL に依存する必要はありません。デフォルト設定では、無効な値を挿入すると、最終的には null 値になります。

新規プロジェクトの実際の状況から判断すると、ステータスフィールドをソートする必要はほとんどありません。 必要になったとしても、テーブル構造を設計するときに順序を設定できるため、デメリット 2 は無視できます。 デメリット 3 は、コード標準、挿入前/更新前検証などを通じて回避できます。 デメリット 1 については、テストを行う必要があります。

テスト準備

まずテーブルを作成します。

テーブル `enum_tests` を作成します (
 `id` int(10) 符号なし NOT NULL AUTO_INCREMENT,
 `status` enum('pending','success','closed') COLLATE utf8mb4_unicode_ci NOT NULL,
 主キー (`id`)
) エンジン=InnoDB デフォルト文字セット=utf8mb4 照合=utf8mb4_unicode_ci;

次に 100 万個のデータを挿入します。

カウント = 1000000;
1000 バイト
$データ = [];
foreach (['保留中', '成功', '終了'] を $status として) {
  $data[$status] = [];
  ($i = 0; $i < $bulk; $i++) の場合 {
    $data[$status][] = ['status' => $status];
  }
}

($i = 0; $i < $count; $i += $bulk) の場合 {
  $status = array_random(['保留中', '成功', '終了']);
  EnumTest::insert($data[$status]);
}

テストプロセス

テスト1#

列挙値リストの最後に払い戻しの値を追加します。

ALTER TABLE `enum_tests` CHANGE `status` `status` ENUM('pending','success','closed','refunded') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;

出力:

クエリは正常、影響を受けた行は 0 行 (0.04 秒)
レコード: 0 重複: 0 警告: 0

結論: 最後に列挙値を追加してもコストはほとんどかかりません。

テスト2:#

追加した値を削除して払い戻し

ALTER TABLE `enum_tests` CHANGE `status` `status` ENUM('pending','success','closed') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;

出力:

クエリは正常、1000000 行が影響を受けました (5.93 秒)
レコード: 1000000 重複: 0 警告: 0

結論: 未使用の列挙値を削除するには、依然としてテーブル全体のスキャンが必要であり、コストはかかりますが、許容範囲内です。

テスト3:#

値のリストの最後ではなく真ん中に払い戻しを挿入します

ALTER TABLE `enum_tests` CHANGE `status` `status` ENUM('pending','success','refunded', 'closed') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;

出力:

クエリは正常、1000000 行が影響を受けました (6.00 秒)
レコード: 1000000 重複: 0 警告: 0

結論: 元の列挙値リストの途中に新しい値を追加するには、テーブル全体のスキャンと更新が必要になり、コストがかかります。

テスト4:#

値のリストの途中にある値を削除する

ALTER TABLE `enum_tests` CHANGE `status` `status` ENUM('pending','success','closed') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;

出力:

クエリは正常、1000000 行が影響を受けました (4.23 秒)
レコード: 1000000 重複: 0 警告: 0

結論: テーブル全体をスキャンする必要があり、コストが非常にかかります。

テスト5:#

ステータスフィールドにインデックスを追加し、上記のテストを実行します。

ALTER TABLE `enum_tests` ADD INDEX(`status`);

テスト 2 ~ 4 の消費時間は実際には増加していることがわかりました。これは、インデックスを同時に更新する必要があることが原因であると考えられます。

結論

新しいプロジェクトでは、新しい列挙値のみが登場します。将来的に一部の状態が放棄されたとしても、列挙値リストを調整する必要はありません。そのため、プロジェクト内の状態を格納するためのデータ型として列挙型を導入することにしました。

<<:  Vueは適切なスライドアウトレイヤーアニメーションを実装します

>>:  Linux でファイルの種類を理解して識別する方法

推薦する

MySQL テーブルを削除するときに外部キー制約を無視するシンプルな実装

テーブルを削除することはあまり一般的ではありませんが、特に外部キーの関連付けがあるテーブルの場合は、...

MySQLの複合インデックス方式の詳細な説明

どの DBMS でも、インデックスは最適化にとって最も重要な要素です。データ量が少ない場合、適切なイ...

Keepalived は Nginx の負荷分散と高可用性のサンプル コードを実装します

第1章: keepalivedの紹介VRRP プロトコルの目的は、静的ルーティングの単一点障害問題を...

MySQL IDは1から増加し始め、不連続IDの問題を素早く解決します

mysql idは1から始まり、不連続なidの問題を解決するために自動的に増加します。強迫性障害の私...

HTML ページをスクロールするときに一部のコンテンツを固定位置に固定する方法

この記事では主に、レイアウトに役立つ、HTML ページ内の一部のコンテンツを固定してスクロール時にス...

mysql の認証、起動、およびサービスの起動のための一般的なコマンド

1. 4つの起動方法: 1.mysqld MySQL サーバーを起動します: ./mysqld --...

js 属性オブジェクトの hasOwnProperty メソッドの使用

オブジェクトの hasOwnProperty() メソッドは、オブジェクトに特定の独自の (継承され...

XHTMLタグは適切に使用する必要があります

<br />123WORDPRESS.COM の以前のチュートリアルでは、Web ページ...

MySQL トリガー: 複数のトリガー操作の作成例の分析

この記事では、例を使用して、MySQL で複数のトリガー操作を作成する方法について説明します。ご参考...

MySQLの整数データ型tinyintの詳細な説明

目次1.1Tinyint型の説明1.2 練習環境の説明1.3 未署名属性の追加1.3.1 SQLモー...

Linux でのログ サーバーの設定に関するグラフィック チュートリアル

序文この記事では、Linux 構成ログ サーバーに関する関連コンテンツを主に紹介し、参考と学習のため...

Dockerを使用してJenkinsをインストールする方法

目次1. イメージをプルする2. ローカルデータボリュームを作成する3. コンテナを作成する4. J...

MySQL UNION演算子の基本知識ポイント

MySQL UNION 演算子このチュートリアルでは、MySQL UNION 演算子の構文と例を紹介...

ボタンを使用してフォームを送信する代わりに、画像を使用してフォームを送信します。

コードをコピーコードは次のとおりです。 <フォームメソッド="post" ...