web-dev-qa-db-ja.com

MySQL-1対1の関係?

MySQLデータベースで1対1の関係を達成しようとしています。たとえば、UsersテーブルとAccountsテーブルがあるとします。また、ユーザーが持つことができるアカウントは1つだけであることを確認します。また、ユーザーごとに1つのアカウントしか存在できないこと。

これには2つの解決策を見つけましたが、何を使うべきかわかりませんし、他の選択肢もあります。

最初の解決策:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    user_id INT UNIQUE,
    PRIMARY KEY(id),
    FOREIGN KEY(user_id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

この例では、ユーザーの主キーを指すアカウントで外部キーを定義します。そして、外部キーを一意にするため、アカウントに2人の同一ユーザーを含めることはできません。テーブルを結合するには、このクエリを使用します。

SELECT * FROM users JOIN accounts ON users.id = accounts.user_id;

2番目の解決策:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id),
    FOREIGN KEY(id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

この例では、主キーから別のテーブルの主キーを指す外部キーを作成します。主キーはデフォルトで一意であるため、この関係は1対1になります。テーブルを結合するには、これを使用できます:

SELECT * FROM users JOIN accounts ON users.id = accounts.id;

今、質問:

  • MySQLで1対1の関係を作成する最良の方法は何ですか?
  • これら2つ以外のソリューションはありますか?

私はMySQL Workbenchを使用しており、EER図で1対1の関係を設計し、MySQL WorkbenchでSQLコードを生成すると、1対多の関係が得られます:Sそれは私を混乱させるものです:S

そして、これらのソリューションのいずれかをMySQL Workbench EERダイアグラムにインポートすると、リレーションが1対多として認識されます:Sこれも混乱を招きます。

したがって、MySQL DDLで1対1の関係を定義する最良の方法は何でしょうか。そして、これを達成するためのオプションは何ですか?

51
Limeni

主キーはデフォルトで一意であるため、この関係は1対1になります。

いいえ、それは関係を「1対0または1」にします。それは実際に必要なものですか?

yesの場合、「2番目の解決策」の方が優れています。

  • より簡単です
  • 必要なストレージが少ない1 (したがって、キャッシュを「大きく」する)
  • 維持するインデックスが少ない2、データ操作に役立つ、
  • および(InnoDBを使用しているため)自然に clusters データであるため、互いに近いユーザーはアカウントも近くに格納されます。これは、キャッシュの局所性と特定の種類の範囲スキャンに役立ちます。

ところで、あなたはaccounts.idこれが機能するための通常の整数(自動インクリメントではない)。

noの場合、以下を参照してください...

MySQLで1対1の関係を作成する最良の方法は何ですか?

「ベスト」はオーバーロードされたWordですが、「標準」ソリューションは他のデータベースと同じです。両方のエンティティ(ユーザーの場合はアカウント)を同じ物理テーブルに配置します。

これら2つ以外のソリューションはありますか?

理論的には、2つのPK間で循環FKを作成できますが、残念ながらMySQLではサポートされていない鶏と卵の問題を解決するためにdeferred制約が必要になります。

そして、これらのソリューションのいずれかをMySQL Workbench EER図にインポートすると、リレーションが1対多として認識されます:Sそれも混乱します。

私はその特定のモデリングツールであまり実用的な経験はありませんが、それは「多くの」側がユニークになることで「多くの」側が1に制限された「1対多」だからだと思います。 「多」は「1または多」を意味せず、「0または多」を意味するため、「キャップ」バージョンは実際には「0または1」を意味することに注意してください。


1 追加フィールドのストレージ費用だけでなく、セカンダリインデックスも同様です。 常にクラスターテーブル であるInnoDBを使用しているため、クラスター化テーブルのセカンダリインデックスは、ヒープベースのテーブルよりもさらに高価であることに注意してください。

2 InnoDB インデックスが必要 外部キー。

40

最初のアプローチでは、accountsテーブルにiduser_idの2つの候補キーを作成します。

したがって、2番目のアプローチ、つまり外部キーを主キーとして使用することをお勧めします。この:

  • 使用する列が1つ少ない
  • 各行を一意に識別できます
  • アカウントとユーザーを一致させることができます
8
Salman A