У нас есть схема устаревшей базы данных, в которой есть несколько интересных дизайнерских решений. До недавнего времени мы поддерживали только Oracle и SQL Server, но мы пытаемся добавить поддержку PostgreSQL, что вызвало интересную проблему. Я искал Qaru и остальную часть Интернета, и я не считаю, что эта конкретная ситуация является дубликатом.
Oracle и SQL Server ведут себя одинаково, когда дело доходит до нулевых столбцов в уникальном ограничении, которое должно по существу игнорировать столбцы, которые являются NULL при выполнении уникальной проверки.
Скажем, у меня есть следующая таблица и ограничение:
CREATE TABLE EXAMPLE
(
ID TEXT NOT NULL PRIMARY KEY,
FIELD1 TEXT NULL,
FIELD2 TEXT NULL,
FIELD3 TEXT NULL,
FIELD4 TEXT NULL,
FIELD5 TEXT NULL,
...
);
CREATE UNIQUE INDEX EXAMPLE_INDEX ON EXAMPLE
(
FIELD1 ASC,
FIELD2 ASC,
FIELD3 ASC,
FIELD4 ASC,
FIELD5 ASC
);
Как на Oracle, так и на SQL Server, любой из столбцов с нулевым значением NULL
приведет только к выполнению проверки уникальности для столбцов, отличных от нуля. Таким образом, следующие вставки можно выполнить только один раз:
INSERT INTO EXAMPLE VALUES ('1','FIELD1_DATA', NULL, NULL, NULL, NULL );
INSERT INTO EXAMPLE VALUES ('2','FIELD1_DATA','FIELD2_DATA', NULL, NULL,'FIELD5_DATA');
-- These will succeed when they should violate the unique constraint:
INSERT INTO EXAMPLE VALUES ('3','FIELD1_DATA', NULL, NULL, NULL, NULL );
INSERT INTO EXAMPLE VALUES ('4','FIELD1_DATA','FIELD2_DATA', NULL, NULL,'FIELD5_DATA');
Однако, поскольку PostgreSQL (правильно) придерживается стандарта SQL, эти вставки (и любая другая комбинация значений до тех пор, пока один из них имеет значение NULL) не будут вызывать ошибку и быть вставлены правильно без проблем. К сожалению, из-за нашей устаревшей схемы и поддерживающего кода нам нужно, чтобы PostgreSQL вел себя так же, как SQL Server и Oracle.
Мне известно о следующем вопросе и его ответах: Создать уникальное ограничение с нулевыми столбцами. По моему мнению, для решения этой проблемы есть две стратегии:
- Создайте частичные индексы, которые описывают индекс в тех случаях, когда нулевые столбцы являются как
NULL
, так иNOT NULL
(что приводит к экспоненциальному росту числа частичных индексов) - Используйте
COAELSCE
со значением дозорного значения для столбцов с нулевым значением в индексе.
Проблема с (1) заключается в том, что количество частичных индексов, которые нам нужно создать, растет экспоненциально с каждым дополнительным столбцом с нулевым значением, который мы хотели бы добавить к ограничению (2 ^ N, если я не ошибаюсь). Проблемы с (2) состоят в том, что контрольные значения уменьшают количество доступных значений для этого столбца и все потенциальные проблемы с производительностью.
Мой вопрос: это единственные два решения этой проблемы? Если да, то каковы компромиссы между ними для данного конкретного случая использования? Хорошим ответом будет обсуждение производительности каждого решения, ремонтопригодность, как PostgreSQL будет использовать эти индексы в простых операциях SELECT
и любых других "gotchas" или вещах, о которых нужно знать. Имейте в виду, что 5 нулевых столбцов были только для примера; у нас есть несколько таблиц в нашей схеме с до 10 (да, я плачу каждый раз, когда вижу это, но это то, что есть).