web-dev-qa-db-ja.com

他の一意のフィールドが存在するのに、なぜ自動インクリメントの主キーを使用するのですか?

私は「データベースシステム」と呼ばれるコースを受講しており、クラスプロジェクトではウェブサイトをデザインする必要があります。

これが私が作成したテーブルの例です:

_CREATE TABLE users
(
  uid INT NOT NULL AUTO_INCREMENT,
  username VARCHAR(60),
  passhash VARCHAR(255),
  email VARCHAR(60),
  rdate DATE,
  PRIMARY KEY(uid)
);
_

教授は、「uid」(ユーザーID)はまったく役に立たず、不要であり、2人のユーザーが同じユーザー名を持つことはできないため、ユーザー名を主キーとして使用する必要があると言いました。

Domain.com/viewuser?id=5のようなものを呼び出すときは、次のようにパラメーターをチェックするだけなので、ユーザーIDを使用すると便利だと彼に言いました。is_numeric($_GET['id'])...言うまでもなく彼はそうではありませんでした納得した。

たくさんのチュートリアルでuser_idや他の同様の属性(thread_id、comment_idなど)を見たり、人気のあるソフトウェア(vbulletinなど)のデータベーススキーマを見たりしたので、他にもたくさんの(より強力な)理由があるはずです。

だから私の質問は:ユーザー名のような別の属性を使用するのではなく、主キーとしてnullではない自動インクリメントIDの必要性をどのように正当化するのでしょうか?

47
cnandreu

主キーの自動インクリメントは、いくつかの理由で役立ちます。

  • StackOverflowのように重複するユーザー名を許可します
  • ユーザー名(またはログインに使用する場合はメールアドレス)を(簡単に)変更できます。
  • 選択、結合、および挿入は、数値インデックスを維持するのがはるかに高速であるため、varchar主キーよりも高速です。
  • あなたが言ったように、検証は非常に簡単になります:if ((int)$id > 0) { ... }
  • 入力のサニタイズは簡単です:$id = (int)$_GET['id']
  • 外部キーが潜在的に大きな文字列値を複製する必要がないため、オーバーヘッドがはるかに少なくなります

自動インクリメントの数字キーがすぐに利用できる場合、レコードの一意の識別子として文字列情報を使用しようとするのは悪い考えだと思います。

一意のユーザー名を持つシステムは、ごく少数のユーザーには問題ありませんが、インターネットによって根本的に壊れています。ウェブサイトとやり取りしなければならない可能性のある「ジョン」という名前の人の数を考えると、それぞれに一意の表示名を使用するように要求するのはばかげています。それは、ユーザー名を飾るランダムな数字と文字で私たちが頻繁に見るひどいシステムにつながります。

ただし、一意のユーザー名を適用するシステムであっても、主キーとしては適切な選択ではありません。 500件の投稿があるユーザーを想像してみてください。postsテーブルの外部キーには、500回複製されたユーザー名が含まれます。誰かが最終的にユーザー名を変更する必要があるかもしれないと考える前でさえ、オーバーヘッドは法外です。

82
meagar

ユーザー名が主キーであり、ユーザーがユーザー名を変更した場合、usersテーブルへの外部キー参照を持つすべてのテーブルを更新する必要があります。

15
Matt Caldwell

各ユーザーに一意の任意の整数を割り当てることがアプリケーションにとって価値があることを教授に示した場合、もちろん、それは「完全に役に立たず、不要」であると言うのは間違いです。

しかし、多分あなたは彼の主張を逃したでしょう。 「2人のユーザーが同じユーザー名を持つことはできない」という要件であると彼が言った場合、あなたはその要件を満たしていません。

SQL DDLを投稿していただき、誠にありがとうございます。非常に便利ですが、ほとんどの場合、SOを気にする必要はありません。

あなたのテーブルを使用して、私はこれを行うことができます:

INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);

その結果:

SELECT uid, username, passhash, email, rdate 
FROM users;

uid   username   passhash   email   rdate
1     <NULL>     <NULL>     <NULL>  <NULL>
2     <NULL>     <NULL>     <NULL>  <NULL>
3     <NULL>     <NULL>     <NULL>  <NULL>
4     <NULL>     <NULL>     <NULL>  <NULL>

教授が言いたかったのは、usernameに自然キーを適用しないと、データの整合性がまったくないということだと思います。

私が教授だった場合は、デザインからnull許容列を削除することもお勧めします。

10
onedaywhen

これは通常 代理キー と呼ばれ、多くの利点があります。その1つは、データベースの関係をアプリケーションデータから隔離することです。詳細と対応する欠点は、上記のwikiリンクにあります。

7
RC.

誰かが自分のユーザー名(またはそのことについては任意の名前)を変更したいと思うかもしれないからです。

4
OMG Ponies

これをバックアップするには、データベースの知識が豊富な人が必要ですが、外部キーのルックアップ時間で応答が速くなると思います。

さらに、後でユーザー名を変更するか、ユーザー名の要件を変更するかを決定する場合があります(おそらくより長い文字列ですか?)。 IDを使用すると、すべての外部キーを変更する必要がなくなります。

それに直面してみましょう。ほとんどのプロジェクトは拡大しませんthatそれほどではありませんが、今すぐ優れたプログラミング標準に準拠できるようになった12か月後に、本当に頭痛の種になるリスクを冒したいと思いますか?

1
zzzzBov

iDを使用してデータの重複を防ぎ、一部のプロセスが複雑にならないようにすることができます(データを更新または削除する場合)。IDを使用すると、より簡単になります。

iDを使用したくない場合は、別のフィールドを使用できます。しかし、それらをユニークにすることを忘れないでください。データの重複を防ぐことができます。

pRIMARY以外の別の方法はUNIQUEです。

0
klox

私は上記のすべての答えに行きます。 IDは実装が簡単で、インデックス作成に関しては、varcharよりもIntが常に優先されます。あなたの教授はもっとよく知っているはずです、なぜ彼はInt idが私の上にいるのにノーと言うのでしょうか!

0
ThinkCode

Useridは一意である(複製できない)と想定されており、インデックスである場合もあるためです。

0
Marware

そして、誰かが盗むことができるように、ユーザー名をクリアテキストで保存しますか?いつか暗号化したい(または今すぐ暗号化したい)自然キーの使用を検討することは決してありません。

0
HLGEM