ユーザーの情報を保持する大きなテーブルと、いくつかの場所を保持する別のテーブルがあるとします。次に、user_idとlocation_idを保持する別のテーブルを使用します。
データを取得するには、左結合クエリを使用する必要があります。これにより、すべてのプロセスを1つのテーブルに収めるよりも、プロセス全体が長くなるのではないでしょうか。たとえば、同じテーブルのテキストとして場所を指定できます。
編集:ここに例があります。
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`gender` enum('M','F') DEFAULT NULL
);
CREATE TABLE `user_location` (
`user_id` int(11) NOT NULL,
`location_id` int(11) NOT NULL
);
CREATE TABLE `location` (
`id` int(11) NOT NULL,
`location` varchar(45),
`parent_id` varchar(45)
);
注:すべての関連フィールドがそれらの間で適切にインデックス付けされていると想定してください。
編集:私は現在、上記のようにジャンクションテーブルを介して場所を取得するユーザーを含む大規模なデータベースを持っています。検索結果が遅いため、データベースの最適化を求められました。 memcache
を追加して大幅に改善しましたが、今は左結合について考えているだけです。
たとえば、現在のクエリは次のようなものです。
SELECT * FROM users
LEFT JOIN user_location
ON user_location.user_id = user.id
LEFT JOIN location
ON location.id = user_location.location_id;
そして、それは単に場所を取得することです。ジャンクションを介して取得される他のいくつかのフィールドがあり、それらはすべてユーザーのプロファイルを表示するために必要です。電話番号、住所、パスワード、D.O.Bなど、さまざまな表があります。
ユーザープロファイルのページを作成するには、サーバーに大きなクエリを送信する必要があります。さて、初回以降はキャッシュされ、問題ありません。しかし、なぜ誰かがそのようなデータベースを構築するのでしょうか。
すべてを1つのテーブルに入れると、大きくて冗長なテーブルになります。
すべてのテーブルが適切にインデックス化されている場合、クエリごとに読み込まれる行の数が少ないため、3つのテーブルのソリューションは高速になります。
ジャンクションテーブルは、リレーショナルデータベースの設計における非常に標準的な手法です。それはデータベース101でカバーされています。2つのエンティティ間に多対多の関係がある場合、それらを表す標準的な方法は3つのテーブルを使用することです。
テーブルの2つは、主キーを持つエンティティテーブルです。ジャンクションテーブルは(論理的に)それらの間にあり、2つの外部キーを含み、1つは各エンティティテーブルを参照します。多くの場合、これらの2つの外部キーは、ジャンクションテーブルの2つの列だけになります。
データベース101を取り上げたことがない限り、なぜこれが良い方法であるかどうか誰もが尋ねる理由を理解できません。
「すべての関連フィールドがそれらの間で適切にインデックス付けされていると想定してください。」いいえ、それはしません。 「複合」インデックスについて聞いたことがないユーザーが多すぎて、その重要性をあまり理解していないようです。
特に、次のものが必要です。
CREATE TABLE user_location(
# No surrogate id for this table
user_id MEDIUMINT UNSIGNED NOT NULL, -- For JOINing to one table
location_id MEDIUMINT UNSIGNED NOT NULL, -- For JOINing to the other table
# Include other fields specific to the 'relation'
PRIMARY KEY(user_id, location_id), -- When starting with user
INDEX (location_id, user_id) -- When starting with location
) ENGINE=InnoDB;
さらに メモは私のブログにあります 。
DBでのアプローチは間違っています。テーブルは、条件なしで列の追加/削除を処理するデータを保持するためのフィールドの束ではありません。 DB構造は分析の結果です。特定の要件から生まれたDbのこの部分:ユーザーは1つ以上の場所に住んでいます。同じ場所に1人以上のユーザーが住むことができます。ユーザーは名前と性別で識別されます。ロケーションはIDで識別されます。この要件に基づいて、ユーザーと場所の2つのエンティティを特定します。これらのエンティティ間の関連付けは多対多であり、概念スキーマをERに変換するため、(少なくとも)UsersLocationsに関する特定のテーブルを取得し、両方のエンティティを指す2つの外部キーで(少なくとも)構成されます。名前は主キーとして使用できないため(Peopleは同じ名前を持つことができるため)、IDを使用します(おそらく自動インクリメント)。
[〜#〜] eav [〜#〜] がある場合、INSERT
location_id =
0または1のデフォルト値を指定するだけで、説明はUndefinedまたはNot Setlocations
テーブル。 user_id
とlocation_id
を含むテーブルで、デフォルトでINSERT
のトリガーを作成します。
そのため、LEFT JOIN
を使用してゆっくり検索する必要はなく、JOIN
を使用するだけです。ユーザーがlocation_id=
を持っている場合、0または1(あなたが取ったもの)はデフォルトのlocation_name
を返します。
ちなみに、LEFT JOIN
構文はインデックスによって異なります。これらのフィールドにインデックスがある場合、users
テーブルが大きくない(仮定)場合、問題は発生しません。