enumデータ型を使用する代わりに新しいデータベーステーブルを作成するのは無駄ですか?


38

私が提供する4種類のサービスがあると仮定します(それらは頻繁に変わることはほとんどありません):

  • テスト中
  • 設計
  • プログラミング
  • その他

上記のカテゴリのいずれかに該当する実際のサービスが60〜80個あるとします。たとえば、「サービス」は「テクニックAを使用したプログラムのテスト」で、タイプは「テスト」です。

それらをデータベースにエンコードしたいです。私はいくつかのオプションを思いつきました:

オプション0:

VARCHAR直接使用して、サービスタイプを文字列として直接エンコードします

オプション1:

データベースを使用しますenum。しかし、enumは悪です

オプション2:

2つのテーブルを使用します。

service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);

参照整合性も楽しむことができます:

ALTER service_line_item 
    ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);

いいですね。

しかし、私はまだ物事をエンコードし、整数を処理する必要があります。つまり、テーブルにデータを入力するときです。または、テーブルにデータを入力または処理するときに、手の込んだプログラミングまたはDB構造を作成する必要があります。つまり、データベースを直接扱うとき、またはプログラミング側で新しいオブジェクト指向エンティティを作成するときにJOINし、それらを正しく操作することを確認します。

オプション3:

使用しないでくださいenum。2つのテーブルを使用せず、整数列を使用してください。

service_line_item (
    id,
    service_type INT,        -- use 0, 1, 2, 3 (for service types)
    description VARCHAR
);

これは、物事のコード側により多くのオーバーヘッドを必要とする「偽の列挙」のようなもの{2 == 'Programming'}です。

質問:

現在、私はコンセプトの下でガイドされているオプション2を使用してそれを実装しました

  1. enumを使用しないでください(オプション1)
  2. データベースをスプレッドシートとして使用しないでください(オプション0)

しかし、プログラミングと認知のオーバーヘッドの点で私にとって無駄だと感じるのは仕方がありません。2つのテーブルを認識し、2つのテーブルを処理する必要があります。

「無駄の少ない方法」のために、私は見ていOption 3ます。ITは軽量であり、動作するために本質的に同じコード構成が必要です(わずかな変更がありますが、複雑さと構造は基本的に同じですが、単一のテーブルを使用します)

私は理想的には常に無駄ではなく、どちらのオプションにも良いケースがあると思いますが、オプション2とオプション3をいつ使用するかについての良いガイドラインはありますか?

タイプが2つしかない場合(バイナリ)

この質問にもう少し追加するために...同じ会場で、「標準」または「例外」サービスのバイナリオプションがあります。これはサービス広告申込情報に適用できます。オプション3を使用してエンコードしました。

値{"Standard"、 "Exception"}を保持するためだけに新しいテーブルを作成しないことにしました。したがって、私の列は{0、1}を保持し、列名はが呼び出されexception、コードは{0, 1} => {STANDARD, EXCEPTION}(プログラミング言語の定数としてエンコードされた)からの翻訳を行っています

これまでのところ、どちらも好きではない.....(オプション2もオプション3も好きではない)。3よりも優れたオプション2が見つかりますが、オーバーヘッドが大きくなります。2と3のうちどのオプションを使用しても、エンコード処理を整数としてエスケープすることはできません。

ORM

回答を読んだ後、コンテキストを追加するために、ORCを(最近)使用し始めました(私の場合はDoctrine 2です)。データセット全体が比較的小さいため、プログラミング構造を使用してその動作を確認したいと考えました。

実際のスプレッドシートから既存のリストがあったのでservice_type、最初にsを入力し、次にservice_line_itemsを入力しました。したがって、「標準/例外」や「テスト」などはすべてスプレッドシート上の文字列であり、DBに保存する前に適切なタイプにエンコードする必要があります。

私はこのSOの答えを見つけました:doctrine2でENUMの代わりに何を使いますか?、DBのenumコンストラクトを使用せず、INTフィールドを使用し、プログラミング言語の「const」コンストラクトを使用してタイプをエンコードすることを提案しました。

しかし、上記のSOの質問で指摘されているように、整数を直接使用することを避け、定義された言語構成要素(定数)を使用できます。

しかし、それでも....どのように回してstringも、ORMを使用している場合でも、型として開始する場合は、最初に適切な型に変換する必要があります。

だから、言うなら$str = 'Testing';、私はまだどこかのようなブロックをどこかに持っている必要があります:

switch($str):
{ 
    case 'Testing':  $type = MyEntity::TESTING; break;
    case 'Other':    $type = MyEntity::OTHER; break;
}

良いことは、整数/マジック番号を処理していないことです(代わりに、エンコードされた一定量を処理します)が、悪いことは、この変換ステップなしで、自動的にデータベースに物を出し入れできないことです。知識。

そして、それは、「物事をエンコードし、整数を処理しなければならない」などのことを言うことによって、私が部分的に意味したものです。(現在、Ocramiusのコメントの後、私は整数を直接扱う必要はありませんが、必要に応じて名前付き定数と定数との変換を処理します)。


9
何をするにしても、#3をしないでください。それを維持するサイコパスは、それらの魔法の数字が何を意味するかを常に把握する必要があります。そうすれば、彼らがあなたの住んでいる場所を知らないことを望みます。blog.codinghorror.com/coding-for-violent-psychopaths
ラバーダック

7
選択肢2が好きです。ルックアップテーブルの急増が気に入らない場合は、1つのテーブルを使用して「ルックアップタイプ」列を追加します。ただし、ルックアップテーブルを作成することは、これを行うための「標準的な」方法です。UIでドロップダウンに簡単にデータを入力するなどの楽しいことを実行できるからです。
ロバートハーヴェイ

ここの投稿で「編集」を使用しないでください。私たちはフォーラムではありません。すべてのStack Exchangeの投稿には、誰でも閲覧できる詳細な編集履歴が既に含まれています。
ロバートハーヴェイ

EDITを使用できない場合、何を使用しますか?
デニス

すでに編集したように、投稿を編集して自然に見せてください。編集履歴を参照して、変更を確認します。
ロバートハーヴェイ

回答:


35

参照テーブルを使用するオプション#2は、標準的な方法です。何百万人ものプログラマーによって使用されており、動作することが知られています。それはパターンですので、あなたのものを見る誰もがすぐに何が起こっているかを知るでしょう。データベース上で動作するライブラリとツールが存在し、多くの作業からあなたを救い、それを正しく処理します。それを使用する利点は無数にあります。

無駄ですか?はい、しかしほんのわずかです。半分まともなデータベースでは、頻繁にこのような頻繁に結合された小さなテーブルを常にキャッシュに保持するため、一般的に無駄はほとんどありません。

説明した他のすべてのオプションは、MySQLを含め、アドホックでハッキングされenumています。これは、SQL標準の一部ではないためです。(それ以外enumは、アイデアそのものではなく、MySQLの実装です。いつか標準の一部としてそれを見るのは気になりません。)

プレーン整数を使用する場合の最後のオプション#3は、特にハッキーです。最悪の事態に陥ります。参照整合性、名前付き値、データベース内の値の意味に関する明確な知識、あらゆる場所に投げられる任意の整数だけです。このトークンにより、コード内の定数の使用をやめ、代わりにハードコードされた値の使用を開始することもできます。circumference = radius * 6.28318530718;。どのようにそのことについて?

参照テーブルがわずらわしいと思う理由を再検討する必要があると思います。私が知っている限り、他の誰も彼らを面倒だとは思わない。それはあなたが仕事に適切なツールを使用していないためだと思われますか?

「ものをエンコードして整数を処理する」、「複雑なプログラミング構造を作成する」、または「プログラミング側で新しいオブジェクト指向エンティティを作成する」という文は、おそらくオブジェクトリレーショナルを実行しようとしている可能性があることを示していますアプリケーションのコード全体にオンザフライでマッピング(ORM)が分散されているか、最良の場合は、Hibernateなどの既存のORMツールをジョブに使用する代わりに、独自のオブジェクトリレーショナルマッピングメカニズムをロールしようとする場合があります。これらはすべて、Hibernateを使用すると簡単です。学習するのに少し時間がかかりますが、学習した後は、アプリケーションの開発に集中でき、データベース上でのデータの表現方法の重要なメカニズムを忘れることができます。

最後に、データベースを直接操作するときに生活を楽にしたい場合、少なくとも2つのことができます。

  1. メインテーブルを参照する参照テーブルと結合するビューを作成し、各行に参照IDだけでなく対応する名前も含まれるようにします。

  2. 参照テーブルに整数IDを使用する代わりに、4文字の略語でCHAR(4)列を使用します。したがって、カテゴリのIDは「TEST」、「DSGN」、「PROG」、「OTHR」になります。(もちろん、それらの説明は適切な英語の単語のままです。)それは少し遅くなりますが、私を信じて、誰も気づかないでしょう。

最後に、2つのタイプしかない場合、ほとんどの人はブール列を使用します。したがって、その「標準/例外」列はブール値として実装され、「IsException」と呼ばれます。


3
余談ですが、Postgresには列挙型もあります。シンプルで特別なものはなく、読み取り可能な文字列を値として使用できますが、より効率的な整数を内部で使用できます。
キャット

データが結果的に繰り返されるが、冗長ではない(たとえば、更新/挿入/削除の異常が発生しない)場合はどうですか?たとえば、人の性別(新しいデータ型を導入する可能性は低い、性別の名前を変更する必要はありませんなど)
アダムトンプソン

これ:最終的には「受け入れ環境」が必要であり、変更しない列挙型を変更する必要があることがわかるからです。
ピーターB

3

プログラミングの終わりに定数または列挙型を持つオプション2。
それは知識を複製し、「真実の単一源」の原則に違反しますが、フェイルファースト手法を使用して対処できます。システムがロードされると、列挙値またはconst値がデータベースに存在することを確認します。そうでない場合、システムはエラーをスローし、ロードを拒否する必要があります。通常、このバグを修正する方が、より深刻な事態が発生した可能性がある場合よりも安価です。


0

[短い]文字列をキーとして使用するのを止めるものは何もないので、テーブル内の名前を読みやすくすることができ、無意味な代理番号のエンコーディングに頼ることはできません。サービスの種類を説明する別のテーブルが必要です。たとえば、アプリケーションが国際化するという偶然のことです。

ユーザーは自分の言語で4つのカテゴリを表示できますが、データベーステーブルには読み取り可能な値が含まれています。データベース構造やコードの変更は必要ありません。

table service_type 
( id VARCHAR 
, name VARCHAR 
  primary key ( id ) 
);
table service_line_item 
( id 
, service_type VARCHAR 
, description VARCHAR
  foreign key ( service_type ) references service_type ( id )
);

select * from service_type ; 

+-------------+----------------+
| id          | name           |
+-------------+----------------+
| Testing     | Testen         |
| Design      | Design         | 
| Programming | Programmierung |
| Other       | Andere         |
+-------------+----------------+

または、フランスの顧客向けに...

update services_types set name = 'Essai'         where id = 'Testing'; 
update services_types set name = 'Conception'    where id = 'Design'; 
update services_types set name = 'Programmation' where id = 'Programming'; 
update services_types set name = 'Autre'         where id = 'Other'; 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.