У меня есть таблица с фильмами. Поля:
id (PK), title, genre, runtime, released_in, tags, origin, downloads
.
Моя база данных не может быть загрязнена дублированными строками, поэтому я хочу обеспечить уникальность. Проблема в том, что разные фильмы могут иметь одинаковое название или даже одинаковые поля, кроме tags
и downloads
. Как обеспечить уникальность?
Я думал о двух способах:
- сделать все поля кроме
downloads
первичного ключа. Я избегаюdownloads
, потому что это JSON, и это, вероятно, повлияет на производительность. - оставьте только
id
первичный ключ, но добавьте уникальное ограничение ко всем остальным столбцам (кроме, опять жеdownloads
).
Я прочитал этот вопрос, который очень похож, но я не совсем понял, что мне делать. В настоящее время эта таблица не связана ни с какими другими таблицами, но в будущем может быть.
На данный момент у меня чуть меньше 20 000 записей, но я ожидаю, что их число будет расти. Я не знаю, имеет ли это какое-то отношение к проблеме.
РЕДАКТИРОВАТЬ: я изменил схему, и вот как я хотел бы создать таблицу:
CREATE TABLE movies (
id serial PRIMARY KEY,
title text NOT NULL,
runtime smallint NOT NULL CHECK (runtime >= 0),
released_in smallint NOT NULL CHECK (released_in > 0),
genres text[] NOT NULL default ARRAY[]::text[],
tags text[] NOT NULL default ARRAY[]::text[],
origin text[] NOT NULL default ARRAY[]::text[],
downloads json NOT NULL,
inserted_at timestamp NOT NULL default current_timestamp,
CONSTRAINT must_be_unique UNIQUE(title,runtime,released_in,genres,tags,origin)
);
Я также добавил timestamp
колонку, но это не проблема, так как я не буду ее трогать. Так что это всегда будет автоматически и уникально.
Ответы:
Ваше определение таблицы выглядит разумным повсюду. Со всеми столбцами ограничение будет работать , как и ожидалось - за опечатки и незначительные различия в правописании, которые могут быть довольно часто я боюсь за исключением. Посмотрите на комментарий @ a_horse .
NOT NULL
UNIQUE
Альтернатива с функциональным уникальным индексом
Другой вариант - это функциональный уникальный индекс (аналогичный тому, что прокомментировал @Dave ). Но я бы использовал
uuid
тип данных для оптимизации размера и производительности индекса.Преобразование из массива в текст не выполняется
IMMUTABLE
(из-за его общей реализации):Следовательно, вам нужна небольшая вспомогательная функция, чтобы объявить ее неизменной:
Используйте его для определения индекса:
SQL Fiddle.
Больше деталей:
Вы можете использовать сгенерированный UUID в качестве PK, но я все равно буду использовать
serial
столбец с его 4 байтами, что просто и дешево для ссылок FK и других целей. UUID будет отличным вариантом для распределенных систем, которым необходимо генерировать значения PK независимо. Или для очень больших столов, но для этого в нашей солнечной системе недостаточно фильмов.Плюсы и минусы
Уникальное ограничение реализуется с помощью уникального индекса по привлеченным столбцов. Сначала поместите соответствующие столбцы в определение ограничения, и у вас будет полезный индекс для других целей в качестве дополнительного обеспечения.
Есть и другие конкретные преимущества, вот список:
Функциональный уникальный индекс является (потенциально много) меньше по размеру, что может сделать это значительно быстрее. Если ваши столбцы не слишком велики, разница не будет большой. Существует также небольшие накладные расходы для расчета.
Конкатенация всех столбцов можно ввести ложные срабатывания (
'foo ' || 'bar' = 'foob ' || 'ar'
, но кажется , что очень маловероятно , для этого случая. Опечатки настолько гораздо более вероятно , что вы можете спокойно игнорировать его здесь.Уникальность и массивы
Массивы должны быть отсортированы последовательно, чтобы иметь смысл в любом уникальном расположении, полагаясь на
=
оператора, потому что'{1,2}' <> '{2,1}'
. Я предлагаю просмотровые таблицы дляgenre
,tag
иorigin
сserial
ПК и уникальными записями, которые позволяют нечеткий поиск элементов массива. Затем:либо реализуйте полностью нормализованные отношения n: m, которые также обеспечивают ссылочную целостность. Уникальность каждого набора ссылок сложнее установить, вы можете использовать
MATERIALIZE VIEW
(MV) с агрегированными массивами в качестве ступеньки.или работать с отсортированными массивами ссылок FK (которые пока не поддерживаются ограничениями FK). Инструменты из дополнительного модуля intarray могут пригодиться:
В любом случае, работая с массивами напрямую или с нормализованной схемой и материализованным представлением, поиск может быть очень эффективным с правильным индексом и операторами:
Если вы используете Postgres 9.4 или новее, рассмотрите
jsonb
вместоjson
.источник
Представьте, что вы с группой друзей, и разговор переходит в кино. Кто-то спрашивает: «Что вы думаете о« Трех мушкетерах »?» Вы отвечаете: "Какой?"
Какая дополнительная информация вам нужна, чтобы быть абсолютно уверенным, что вы оба думаете об одном и том же фильме? Имя директора? Производственная студия? Год, когда он был выпущен? Одно из звёздных имен? Какая-то комбинация из двух или более?
Ответ на мой и ваш вопрос один и тот же.
Однако я не думаю, что жанр будет хорошим кандидатом. Одна из причин, жанр слишком субъективный критерий. Акция «Три мушкетера»? драма? приключение? комедии? приключенческий? романтическая комедия? Я часто вижу один и тот же фильм в разных жанрах. Даже если вы разрешите использовать несколько жанров, ваш пользователь может выбрать совершенно другой, не указанный в списке фильмов, которые он ищет.
Даже время выполнения может отличаться, особенно в кинотеатрах и версиях VCR / DVD / b-ray.
Поэтому вам нужны жесткие, объективные атрибуты, которые не будут меняться от одного медиа-релиза к другому. К сожалению, это может исключить название фильма, так как известно, что фильмы переименовываются, особенно после выхода сиквела.
Как насчет даты выпуска? Театральный выпуск 1993 года? Видеомагнитофон выпуска 1999 года? Выпуск DVD 2004 года? Вы поняли идею.
Если подумать, что за фильмы, снятые Аланом Смити? Неужели настоящий режиссер когда-нибудь вышел вперед, чтобы поставить свое имя в проекте после свершившегося факта? Я не знаю.
Хм, я бы лучше остановился, пока еще есть некоторые критерии.
Некоторые дополнительные пункты:
источник
Столбец ID не имеет никакого преимущества, если речь идет об уникальности, которую вы хотите / должны применять. Уникальность любой комбинации атрибутов никогда не будет реализована путем добавления бессмысленного идентификатора. Его «преимущество» проявляется только в том случае, если вам когда-нибудь понадобится новая таблица, для которой нужен внешний ключ. В этом случае, и если вы включили Id, вы можете использовать его в качестве FK в новой таблице. (Но не думайте, что это будет бесплатный обед. Недостатком такого подхода является то, что вы, скорее всего, будете писать больше соединений для простой цели получения информации, которая вполне могла бы быть частью этой новой таблицы, которую вы создали. )
источник