16

私は現在、顧客およびWebサイト管理アプリケーション用のデータベーステーブルを設計中です。私の質問は、テーブルの機能部分としての主キーの使用に関するものです(そして、理由だけですべてのテーブルに「ID」番号を割り当てるわけではありません)。

たとえば、これまでのデータベースの4つの関連テーブルを次に示します。そのうちの1つは従来の主キー番号を使用し、他のテーブルは主キーとして一意の名前を使用します。

--
-- website
--
CREATE TABLE IF NOT EXISTS `website` (
  `name` varchar(126) NOT NULL,
  `client_id` int(11) NOT NULL,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `notes` text NOT NULL,
  `website_status` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`),
  KEY `client_id` (`client_id`),
  KEY `website_status` (`website_status`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- website_status
--
CREATE TABLE IF NOT EXISTS `website_status` (
  `name` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `website_status` (`name`) VALUES
('demo'),
('disabled'),
('live'),
('purchased'),
('transfered');

--
-- client
--
CREATE TABLE IF NOT EXISTS `client` (
  `id` int(11) NOT NULL auto_increment,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `client_status` varchar(26) NOT NULL,
  `firstname` varchar(26) NOT NULL,
  `lastname` varchar(46) NOT NULL,
  `address` varchar(78) NOT NULL,
  `city` varchar(56) NOT NULL,
  `state` varchar(2) NOT NULL,
  `zip` int(11) NOT NULL,
  `country` varchar(3) NOT NULL,
  `phone` text NOT NULL,
  `email` varchar(78) NOT NULL,
  `notes` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `client_status` (`client_status`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- client_status
---
CREATE TABLE IF NOT EXISTS `client_status` (
  `name` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `client_status` (`name`) VALUES
('affiliate'),
('customer'),
('demo'),
('disabled'),
('reseller');

ご覧のとおり、4つのテーブルのうち3つは、主キーとして「名前」を使用しています。これらは常にユニークであることを私は知っています。2つのケース(* _statusテーブル)では、ステータスオプションが将来変更される可能性があるため、基本的にENUMの動的置換を使用しています。また、「website」テーブルの場合、Webサイトの「name」は常に一意であること。

これが健全な論理なのか、名前が常に一意の識別子になることがわかっているときにテーブルIDを削除するのか、それとも災害のレシピなのか疑問に思います。私はベテランのDBAではないので、フィードバックや批評などは非常に役立ちます。

これを読んでくれてありがとう!

4

11 に答える 11

18

ルックアップ/ENUMテーブルに常にID番号を追加する理由は2つあります。

  1. 名前で単一の列テーブルを参照している場合は、制約を使用する方が適切な場合があります。
  2. client_statusエントリの1つの名前を変更したい場合はどうなりますか?たとえば、名前を「アフィリエイト」から「アフィリエイトユーザー」に変更する場合は、クライアントテーブルを更新する必要がありますが、これは不要です。ID番号は参照として機能し、名前は説明です。

Webサイトの表で、名前が一意であると確信している場合は、主キーとして使用しても問題ありません。個人的には、外部キーテーブルで使用されるスペースが減り、管理が容易になるため、数値IDを割り当てます。

編集:上記のように、ウェブサイト名の名前を変更すると問題が発生します。これを主キーにすることで、後日変更することが不可能ではないにしても非常に困難になります。

于 2009-05-29T10:07:05.557 に答える
13

自然なものを作るときPRIMARY KEYは、それらの独自性があなたの管理下にあることを確認してください。

一意性違反が発生しないことが絶対に確実な場合は、これらの値をPRIMARY KEY「」として使用してもかまいません。

website_statusclient_statusはあなただけが生成して使用しているように見えるので、PRIMARY KEYキーを長くするとパフォーマンスに影響を与える可能性がありますが、として使用することは許容されます。

website名前は外の世界の支配下にあるようです、それで私はそれをプレーンフィールドにします。名前を変更したい場合はどうなりwebsiteますか?

反例はコードです。それらSSNZIP生成するのはあなたではなく、それらが複製されないという保証はありません。

于 2009-05-29T10:06:34.543 に答える
9

Kimberly Trippには、クラスター化インデックスの作成とプライマリキーの選択の問題(関連する問題ですが、必ずしも完全に同じとは限りません)に関する優れた一連のブログ記事(主キーおよび/またはクラスター化キーとしてのGUIDとクラスター化インデックスの議論が続く)があります。 )。彼女の推奨事項は、クラスター化インデックス/主キーは次のようにすることです。

  1. ユニーク(そうでなければキーとして役に立たない)
  2. ナロー(キーはすべての非クラスター化インデックス、および外部キー関係で使用されます)
  3. 静的(関連するすべてのレコードを変更する必要はありません)
  4. 常に増加します(したがって、新しいレコードは常にテーブルの最後に追加され、中央に挿入する必要はありません)

「名前」をキーとして使用すると、#1は満たされるように見えますが、他の3つはどれも満たされません。

「ルックアップ」テーブルの場合でも、上司がすべてのアフィリエイトパートナーに変更することにした場合はどうなりますか?この値を使用するデータベース内のすべての行を変更する必要があります。

パフォーマンスの観点から、私はおそらくキーが狭いことを最も懸念しています。Webサイト名が実際に長いURLである場合、クラスター化されていないインデックス、およびそれを外部キーとして使用するすべてのテーブルのサイズが実際に肥大化する可能性があります。

于 2009-05-29T14:44:12.190 に答える
3

すでに述べた他のすべての優れた点に加えて、SQL Serverでクラスタリングキーとして大きなフィールドを使用しないようにもう1つ注意が必要です(SQL Serverを使用していない場合、これはおそらく当てはまりません)。 。

これを追加するのは、SQL Serverでは、デフォルトでテーブルの主キーがクラスタリングキーでもあるためです(必要に応じて変更できますが、ほとんどの場合、変更されません)。

SQL Serverテーブルの物理的な順序を決定するクラスタリングキーも、そのテーブル上のすべての非クラスター化インデックスに追加されます。数百から数千の行と1つまたは2つのインデックスしかない場合、それは大したことではありません。ただし、数百万行の非常に大きなテーブルがあり、クエリを高速化するためにインデックスが多数ある可能性がある場合、これにより、実際に大量のディスク領域とサーバーメモリが不必要に浪費されます。

たとえば、テーブルに1,000万行、10個の非クラスター化インデックスがあり、クラスター化キーが4バイトではなく26バイト(INTの場合)である場合、10mioを無駄にしています。10 x 22バイトで合計22億バイト(または約2.2 Gバイト)-これはもはやピーナッツではありません!

繰り返しますが、これはSQL Serverにのみ適用され、クラスター化されていないインデックスが多数ある非常に大きなテーブルがある場合にのみ適用されます。

マーク

于 2009-05-29T11:06:57.167 に答える
2

「一意性違反が発生しないことが絶対に確実な場合は、これらの値を主キーとして使用しても問題ありません。」

一意性違反が発生しないことが絶対に確実な場合は、わざわざキーを定義しないでください。

于 2009-07-02T21:41:19.157 に答える
1

個人的には、このアイデアを使用すると問題が発生すると思います。親子関係が増えると、名前が変わると(遅かれ早かれいつもそうなるので)膨大な量の作業が必要になります。Webサイトの名前が変更されたときに、数千行の子テーブルを更新する必要がある場合、パフォーマンスが大幅に低下する可能性があります。そして、これらの変更が確実に行われるようにする方法を計画する必要があります。それ以外の場合、Webサイト名の変更(名前の有効期限が切れて他の誰かが購入した)は、外部キーの制約のために壊れるか、システム全体に変更を伝播するために自動化された方法(カスケード更新)を行う必要があります。カスケード更新を使用すると、大規模な変更が処理されているときに、システムが突然完全に停止する可能性があります。これは良いこととは見なされません。リレーションシップにIDを使用し、名前フィールドに一意のインデックスを設定して一意性を維持する方が、実際にはより効果的かつ効率的です。データベースの設計では、データの整合性の維持と、それがパフォーマンスにどのように影響するかを考慮する必要があります。

考慮すべきもう1つのことは、Webサイト名は数文字より長くなる傾向があるということです。これは、結合にidフィールドを使用することと、結合に名前を使用することのパフォーマンスの違いが非常に重要になる可能性があることを意味します。数百万のレコードがタイムアウトしている本番システムがあり、データベースを完全に再構築してすべてのSQLを書き換える場合、IDに変更するには遅すぎるため、設計段階でこれらのことを考慮する必要があります。コード。サイトを再び機能させるために15分で修正できるものではありません。

于 2009-05-29T14:31:52.043 に答える
1

これは本当に悪い考えのようです。列挙型の値を変更する必要がある場合はどうなりますか?アイデアは、フラットファイルのセットではなく、リレーショナルデータベースにすることです。この時点で、なぜclient_statusテーブルがあるのですか?さらに、アプリケーションでデータを使用している場合は、GUIDやINTなどの型を使用することで、型を検証し、(型を検証する限り)不正なデータを回避できます。したがって、ハッキングを阻止するのは多くの行の1つです。

于 2009-05-29T14:43:09.057 に答える
1

少し遅くても、破損に強いデータベースの方が、そうでないデータベースよりも優れていると私は主張します。

一般に、代理キー(任意の数値識別子など)はデータベースの整合性を損ないます。主キーは、データベース内の行を識別する主な方法です。主キーの値に意味がない場合、制約には意味がありません。したがって、代理主キーを参照する外部キーも疑わしいです。個々の行を取得、更新、または削除する必要がある場合(および、1つだけに影響することが保証されている場合)は常に、主キー(または別の候補キー)を使用する必要があります。意味のある代替キーがある場合に代理キー値を理解する必要があることは、ユーザーとアプリケーションにとって冗長で潜在的に危険な手順です。

一意性を確保するために複合キーを使用することを意味する場合でも、可能な限り、意味のある自然な属性のセットを主キーとして使用することをお勧めします。とにかく属性を記録する必要がある場合は、なぜ別の属性を追加するのですか?とはいえ、自然で、安定していて、簡潔で、一意であることが保証されているキーがない場合(たとえば、人の場合)、代理キーは問題ありません。

DBMSでサポートされている場合は、インデックスキー圧縮の使用を検討することもできます。これは、特に複合キーのインデックス(トライデータ構造を考えてください)の場合、特に最も選択性の低い属性がインデックスの最初に表示される場合に非常に効果的です。

于 2009-05-30T07:15:31.123 に答える
1

私はcheduardoに同意していると思います。データベース設計のコースを受講してから25年になりますが、データベースエンジンは、文字キーを使用するインデックスをより効率的に管理およびロードできると言われたことを思い出します。キーが変更されたときに何千ものレコードを更新する必要があり、追加されたすべてのスペースが長いキーによって占有されてからシステム間で転送される必要があるというデータベースに関するコメントは、キーが実際にレコードに保存されていることを前提としています。とにかくシステム間で転送する必要はありません。テーブルの列にインデックスを作成する場合、値がテーブルのレコードに格納されるとは思いません(そうするためのオプションを設定しない限り)。

テーブルの自然キーがある場合、それが時々変更されたとしても、別のキーを作成すると冗長性が作成され、データの整合性の問題が発生する可能性があり、実際には、システム間で保存および転送する必要のあるさらに多くの情報が作成されます。私は、ローカルアプリケーションの設定をデータベースに保存することを決定したチームで働いています。各設定のID列、セクション名、キー名、およびキー値があります。2回表示されないように設定を保存するためのストアドプロシージャ(別の聖戦)があります。設定のIDを使用するケースはまだ見つかっていません。ただし、同じセクションとキー名を持つ複数のレコードが作成されたため、アプリケーションが失敗しました。そして、はい、私はそれが列に制約を定義することによって回避できたかもしれないことを知っています。

于 2012-12-27T15:56:04.063 に答える
0

ここで、テーブル内のキーを決定する前に、いくつかの点を考慮する必要があります。

  • 参照(外部キー)を使用する場合は数字キーの方が適しています。外部キーを使用しないため、数字以外のキーを使用しても問題ありません。

  • 非数字キーは数字キーよりも多くのスペースを使用するため、パフォーマンスが低下する可能性があります。

  • 数値キーを使用すると、dbがわかりやすくなります(最後の行を見るだけで、行がないことを簡単に知ることができます)
于 2009-05-29T10:20:15.060 に答える
-1

あなたが働いている会社が突然成長して爆発するとき、あなたは決して知りません、そしてあなたは一晩で5人の開発者を雇わなければなりません。最善の策は、数値(整数)の主キーを使用することです。これは、チーム全体が作業しやすく、データベースが大きくなった場合にパフォーマンスを向上させるためです。レコードを分割してパーティション化する必要がある場合は、主キーを使用することをお勧めします。日時スタンプ付きのレコードを追加していて(すべてのテーブルがそうであるように)、コードのどこかにそのフィールドを誤って更新するエラーがある場合、レコードが正しい順序で入力されたかどうかを確認する唯一の方法は、プライマリをチェックすることですキー。INT主キーを使用するTSQLまたはデバッグの理由はおそらく10以上ありますが、その中でも特に、テーブルに入力された最後の5つのレコードを選択するための単純なクエリを記述しています。

于 2018-04-24T18:03:20.980 に答える