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 でファイルの種類を理解して識別する方法

推薦する

Kubernetes オブジェクトボリュームの詳細な使用方法

概要ボリュームは、さまざまなストレージ リソースを抽象化および仮想化したものです。ストレージ リソー...

Linux にバイナリ MySQL をインストールして MySQL パスワードをクラックする方法

1. システムに必要な libaio ソフトウェアがインストールされていることを確認します。インスト...

MySQL 5.7.18 マスタースレーブレプリケーション設定(マスター 1 台とスレーブ 1 台)チュートリアルの詳細な説明

1. 複製原理マスター サーバーはバイナリ ログ ファイルに更新を書き込み、ログのローテーションを追...

MySql の集計関数に条件式を追加する方法

MySQL のフィルタリングのタイミングは、集計関数で使用される where 条件と having ...

MySQLクエリツリー構造方式

目次MySQL クエリツリー構造1. ツリー構造について2. MySQLでカスタム関数を定義する方法...

Vueは大画面ページのスクリーン適応を実現します

この記事では、大画面ページのスクリーンアダプテーションを実現するためのVueの具体的なコードを参考ま...

HTMLでは、div内のコンテンツが次のサイズを超えたときに自動的にスクロールバーが表示されるように設定します。

HTML ページでは、div 内のコンテンツが制限を超えた後に自動的にスクロール バーを表示する必要...

Windows 10 に付属する仮想マシンのネットワークを設定するための詳細な手順 (グラフィック チュートリアル)

1. サーバー ホストをクリックし、右側の操作リストで [仮想スイッチ管理] をクリックして、仮想...

SQL重複排除方法の概要

SQL を使用してデータを抽出する場合、テーブル内で重複した値に遭遇することがよくあります。たとえ...

MySQL における主キーが 0 であることと主キーの自己選択制約の関係についての詳しい説明 (詳細)

序文この記事は主にMySQLの主キー0と主キー自己排除制約の関係を紹介し、皆さんの参考と学習のために...

React Nativeがシミュレータにリンクできない件について

React Native は、現在人気のオープンソース JavaScript ライブラリ React...

MySQLの起動失敗の解決策

MySQLの起動失敗の解決策MySQLを起動できませんmysqlを停止した後、いくつかの操作(ホスト...

HTML ドキュメントに CSS を埋め込む一般的な 3 つの方法

HTMLでCSSを定義するには、埋め込み、リンク、インラインの3つの方法が一般的に使用されます。 1...

Mysql 5.7.17 をインストールした後、MySQL にログインするチュートリアル

mysql-5.7.17 のインストールについては記事の下部で紹介されているので、参考にしてください...

MySQL Shell import_tableデータインポートの実装

目次1. import_tableの紹介2. データのロードとテーブル関数のインポートの例2.1 L...