Оставьте только одно из этих UNIQUE
ограничений - нет необходимости иметь оба. Когда строка терпит неудачу UNIQUE KEY (from_user_id, to_user_id)
, она также терпит неудачу UNIQUE KEY (to_user_id, from_user_id)
и наоборот, поэтому они логически эквивалентны. Даже с одним ограничением UNIQUE
при попытке представить отношения между Алисой и Бобом вы можете иметь не более одной строки {Алиса, Боб}, и не более одной строки {Боб, Алиса}.
Что касается производительности (то есть обхода отношений в обоих направлениях), вы можете рассмотреть возможность индексации {from_user_id, to_user_id}
(для "прямого" обхода) и / или {to_user_id, from_user_id}
(для "обратного" обхода). Вы можете даже отказаться от суррогатного первичного ключа (relationship_id
) и перейти к естественному PK, что снизит потребность в индексации (вторичные индексы дороги для кластеризованных таблиц, см. Общие сведения о кластерных индексах InnoDB , раздел «Недостатки» кластеризации ").
На мой взгляд, ваша таблица должна выглядеть так:
CREATE TABLE relationships (
from_user_id MEDIUMINT UNSIGNED NOT NULL,
to_user_id MEDIUMINT UNSIGNED NOT NULL,
relationship_level DECIMAL(1,1) NOT NULL,
PRIMARY KEY (from_user_id, to_user_id), -- InnoDB is clustered, so naturally "covers" relationship_level as well.
FOREIGN KEY (from_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION,
FOREIGN KEY (to_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION,
INDEX relationship_to_from (to_user_id, from_user_id, relationship_level) -- Including relationship_level may or may not be a good idea.
) ENGINE=INNODB;
ПРИМЕЧАНИЕ. Включите ли вы relationship_level
в INDEX или нет, зависит от того, хотите ли вы сканирование только по индексу в обратном направлении. «Прямое» направление естественно покрывается PK (поскольку InnoDB кластеризовано ).