Подтвердить что ты не робот

MySQL - отношение один к одному?

Теперь я знаю, что есть некоторые ответы об отношениях "один на один", но ни один из них не ответил на мой вопрос, поэтому, пожалуйста, прочитайте это до голосования:)

Я пытаюсь достичь отношения "один к одному" в базе данных MySQL. Например, допустим, что у меня есть таблица "Пользователи" и "Таблица учетных записей". И я хочу быть уверенным, что Пользователь может иметь только одну учетную запись. И что может быть только одна учетная запись для каждого пользователя.

Я нашел два решения для этого, но не знаю, что использовать, и есть ли другие варианты.

Первое решение:

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;

В этом примере я определяю внешний ключ в аккаунтах, указывающих на первичный ключ у пользователей. И тогда я делаю внешний ключ UNIQUE, поэтому в аккаунтах могут быть два одинаковых пользователя. Чтобы присоединиться к таблицам, я бы использовал этот запрос:

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

Второе решение:

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;

В этом примере я создаю внешний ключ, который указывает от первичного ключа на первичный ключ в другой таблице. Поскольку первичные ключи по умолчанию UNIQUE, это делает это отношение "один к одному". Чтобы присоединиться к таблицам, я могу использовать это:

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

Теперь вопросы:

  • Каков наилучший способ создания отношений One to One в MySQL?
  • Есть ли другие решения, кроме этих двух?

Я использую MySQL Workbench, и когда я создаю отношения One To One на диаграмме EER и позволяю MySQL Workbench создавать SQL-код, я могу получить отношение "Один к многим": S Что меня смущает: S

И если я импортирую какое-либо из этих решений в диаграмму EER MySQL Workbench, он распознает отношения как от одного до многих: S Thats также запутывает.

Итак, что было бы лучшим способом определить отношения Один к одному в MySQL DDL. И какие варианты есть для этого?

Спасибо!!

4b9b3361

Ответ 1

Поскольку первичные ключи по умолчанию UNIQUE, это делает это отношение "один к одному".

Нет, это делает отношение "один к нулю или одному". Это то, что вам действительно нужно?

Если да, тогда ваше "второе решение" лучше:

  • проще,
  • занимает меньше памяти 1 (и, следовательно, делает кеш "больше" )
  • hes меньше индексов для поддержки 2 что приносит пользу манипуляции с данными,
  • и (поскольку вы используете InnoDB), естественно clusters данные, поэтому пользователи, которые находятся рядом друг с другом, будут иметь свои учетные записи, хранящиеся вместе вместе, что может принести пользу местоположению кеша и определенным видам сканирования диапазона.

Кстати, вам нужно сделать accounts.id обычное целое число (не автоинкремент), чтобы это работало.

Если нет, см. ниже...

Каков наилучший способ создания отношений One to One в MySQL?

Ну, "лучше" - это перегруженное слово, но "стандартное" решение будет таким же, как в любой другой базе данных: поместите обе сущности (пользователь и учетная запись в вашем случае) в ту же физическую таблицу.

Существуют ли другие решения, кроме этих двух?

Теоретически, вы можете сделать круговые FK между двумя ПК, но для этого потребуются отложенные ограничения для решения проблемы курица и яйцо, которые, к сожалению, не поддерживаются в MySQL.

И если я импортирую какое-либо из этих решений в диаграмму EER MySQL Workbench, он распознает отношения как от одного до многих: S Thats также запутывает.

У меня не так много практического опыта с этим конкретным инструментом моделирования, но я предполагаю, что это потому, что он "один для многих", где "многие" были ограничены 1, сделав его уникальным. Помните, что "много" не означает "1 или много", это означает "0 или много", поэтому "ограниченная" версия действительно означает "0 или 1".


1 Не только в расходах на хранение для дополнительного поля, но и для вторичного индекса. И поскольку вы используете InnoDB, который всегда кластерные таблицы, будьте осторожны, что вторичные индексы еще более дороги в кластерных таблицах, чем в таблицах с кучей.

2 InnoDB требует индексов по внешним ключам.

Ответ 2

Ваш первый подход создает два ключа-кандидата в таблице учетных записей: id и user_id.

Поэтому я предлагаю второй подход, то есть использование внешнего ключа в качестве первичного ключа. Это:

  • использует один меньше столбца
  • позволяет однозначно идентифицировать каждую строку
  • позволяет вам сопоставлять учетную запись с пользователем

Ответ 3

Как насчет следующего подхода

  • Создать пользователя таблицы

    CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  • Создайте учетную запись таблицы с уникальным индексом user_id и account_id с отношением внешнего ключа к пользователю/учетной записи и первичным ключом на user_id and account_id

    CREATE TABLE `account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  • Создать таблицу user2account

    CREATE TABLE `user2account` (
      `user_id` int(11) NOT NULL,
      `account_id` int(11) NOT NULL,
      PRIMARY KEY (`user_id`,`account_id`),
      UNIQUE KEY `FK_account_idx` (`account_id`),
      UNIQUE KEY `FK_user_idx` (`user_id`),
      CONSTRAINT `FK_account` FOREIGN KEY (`account_id`) REFERENCES         `account` (`id`),
      CONSTRAINT `FK_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

Хотя это решение имеет наибольший след в базе данных, есть некоторые преимущества.

  • Помещение FK_Key в пользовательскую таблицу или в таблицу учетных записей - это то, что я ожидаю от одного до многих релизов (у пользователя есть много учетных записей...)
  • Хотя этот подход user2account в основном используется для определения отношения многих ко многим, добавление ограничения UNIQUE на user_id и на account_id предотвратит создание чего-то другого, кроме отношения один к одному.

Основное преимущество, которое я вижу в этом решении, заключается в том, что вы можете разделить работу в разных слоях кода или подразделениях в компании

  • Отдел A отвечает за создание пользователей, это возможно даже без разрешения на запись в таблицу счетов.
  • Департамент B отвечает за создание учетных записей, это возможно даже без разрешения на запись в таблицу пользователя
  • Депозит C отвечает за создание сопоставления, это возможно даже без разрешения на запись для пользователя или таблицы учетных записей
  • После того, как Депозит C создал сопоставление, ни пользователь, ни учетная запись не могут быть удалены отделом A или B без запроса департамента C, чтобы сначала удалить отображение.