Я понимаю, что есть принятый ответ, хотя я хотел предложить альтернативный подход.Будучи новичком в моей нынешней должности, я не знаком со всеми бизнес-решениями, которые стоят за декларациями первичных ключей на нашем складе.Я разработал подход типа регистрации для отслеживания попыток удаления дублирующихся строк с течением времени.Вот основные особенности этого дизайна:
- Всегда в курсе, учитывая текучую природу DDL / DML
- Новые / удаленные таблицы
- Новые / обновленныепервичные ключи
- Новые / обновленные / удаленные строки
- Самонасыщенная история
- Отслеживание улучшений со временем
- Обеспечивает основу для трендованализ на всех уровнях
- Простой запрос таблиц назначения для исследовательских целей
- Самостоятельное объединение с предложением HAVING или поиск ключевых столбцов не требуется
- Адреса только первичных ключей в это время
- Может быть легко расширен до адреса уникальных ограничений (CONTYPE = 'u' в _V_RELATION_KEYDATA)
Что следуетэто все, что требуется с точки зрения Netezza.Где отмечено, вам нужно будет заполнить пробелы для создания динамического SQL.
Сначала я создал таблицу, которая отслеживает базу данных, таблицу и внутренний идентификатор строки всех дублированных записей.
CREATE TABLE
NZ_DUPLICATE_PKS
(
DATABASE_NAME CHARACTER VARYING(128) NOT NULL
,TABLE_OWNER CHARACTER VARYING(128) NOT NULL
,TABLE_NAME CHARACTER VARYING(128) NOT NULL
,ROW_ID BIGINT NOT NULL
,CURRENT_RECORD_INDICATOR CHARACTER(1) NOT NULL
,CREATE_TIMESTAMP TIMESTAMP NOT NULL
,LAST_UPDATE_TIMESTAMP TIMESTAMP NOT NULL
)
DISTRIBUTE ON
(
ROW_ID
);
ПРИМЕЧАНИЕ : YMMV для ключа распределения и объема строк, входящих в таблицу.Идентификаторы строк в нашем приложении Netezza имели достаточно естественное распределение, что хорошо мне помогало на базе Mustang NPS 10050.
Затем была создана промежуточная версия этой таблицы:
CREATE TABLE
STG_NZ_DUPLICATE_PKS
(
DATABASE_NAME CHARACTER VARYING(128)
,TABLE_OWNER CHARACTER VARYING(128)
,TABLE_NAME CHARACTER VARYING(128)
,ROW_ID BIGINT
,CURRENT_RECORD_INDICATOR CHARACTER(1)
,CREATE_TIMESTAMP TIMESTAMP
,LAST_UPDATE_TIMESTAMP TIMESTAMP
)
DISTRIBUTE ON
(
ROW_ID
);
Затем я создал динамические запросы из системных представлений, чтобы заполнить промежуточную таблицу.Вот базовый запрос, с которого я начал:
SELECT
DATABASE
,OWNER
,RELATION
,CONSTRAINTNAME
,ATTNAME
FROM
{YOUR_DATABASE_NAME}._V_RELATION_KEYDATA
WHERE
CONTYPE = 'p'
-- Exclude the duplicate tracking table
AND RELATION != 'NZ_DUPLICATE_PKS'
ORDER BY
DATABASE
,OWNER
,RELATION
,CONSTRAINTNAME
,CONSEQ
;
Теперь я перебираю базовый запрос для динамического создания запросов на вставку.Мой магазин использует DataStage, чей подход эзотеричен, и здесь его не стоит подробно объяснять.
ПРИМЕЧАНИЕ : Здесь требуется небольшая работа для создания цикла и построения динамического SQL.Можно использовать множество разновидностей shell, Perl, Python и т. Д. Используя пример таблицы с ключом из двух столбцов, вот что нужно построить для вставки в промежуточную таблицу:
INSERT
INTO
STG_NZ_DUPLICATE_PKS
(
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
,CURRENT_RECORD_INDICATOR
,CREATE_TIMESTAMP
,LAST_UPDATE_TIMESTAMP
)
SELECT
'{YOUR_DATABASE_NAME}' DATABASE_NAME
,'{YOUR_TABLE_OWNER}' TABLE_OWNER
,'{YOUR_TABLE_NAME}' TABLE_NAME
,DUPS.ROWID ROW_ID
,'Y' CURRENT_RECORD_INDICATOR
,CURRENT_TIMESTAMP CREATE_TIMESTAMP
,CURRENT_TIMESTAMP LAST_UPDATE_TIMESTAMP
FROM
{YOUR_TABLE_NAME} DUPS
INNER JOIN
(
SELECT
{KEY_COLUMN_1}
,{KEY_COLUMN_2}
FROM
{YOUR_TABLE_NAME}
GROUP BY
{KEY_COLUMN_1}
,{KEY_COLUMN_2}
HAVING
COUNT(*) > 1
)
KEYS
ON
DUPS.{KEY_COLUMN_1} = KEYS.{KEY_COLUMN_1}
AND DUPS.{KEY_COLUMN_2} = KEYS.{KEY_COLUMN_2};
После циклического перебора всех таблиц вЗаполняя промежуточную таблицу, я запускаю серию запросов, рассматривая базу данных, владельца, имя таблицы и идентификатор строки как медленно меняющееся измерение.Записи даты окончания этого запроса в целевой таблице, которых нет в промежуточной таблице:
UPDATE
NZ_DUPLICATE_PKS
SET
CURRENT_RECORD_INDICATOR = 'N'
,LAST_UPDATE_TIMESTAMP = CURRENT_TIMESTAMP
WHERE
CURRENT_RECORD_INDICATOR = 'Y'
AND
(
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
)
NOT IN
(
SELECT
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
FROM
STG_NZ_DUPLICATE_PKS
)
;
Наконец, вставьте последние записи в целевую таблицу:
INSERT
INTO
NZ_DUPLICATE_PKS
(
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
,CURRENT_RECORD_INDICATOR
,CREATE_TIMESTAMP
,LAST_UPDATE_TIMESTAMP
)
SELECT
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
,CURRENT_RECORD_INDICATOR
,CREATE_TIMESTAMP
,LAST_UPDATE_TIMESTAMP
FROM
STG_NZ_DUPLICATE_PKS
WHERE
(
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
)
NOT IN
(
SELECT
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,ROW_ID
FROM
NZ_DUPLICATE_PKS
WHERE
CURRENT_RECORD_INDICATOR = 'Y'
)
;
ПРИМЕЧАНИЕ: Наша среда не такова, что необходима модель только для вставки.Ветераны Netezza будут знакомы с этой мыслью.Если ваша среда только для вставки, измените стратегию соответствующим образом.
Как только все будет готово, очень просто найти повторяющиеся строки для исследования:
SELECT
*
FROM
{YOUR_TABLE_NAME}
WHERE
ROWID IN
(
SELECT
ROW_ID
FROM
NZ_DUPLICATE_PKS
WHERE
CURRENT_RECORD_INDICATOR = 'Y'
AND DATABASE_NAME = '{YOUR_DATABASE_NAME}'
AND TABLE_OWNER = '{YOUR_OWNER_NAME}'
AND TABLE_NAME = '{YOUR_TABLE_NAME}'
);
Мне это нравится, потому что это просто иТо же самое для всех таблиц, независимо от различий в объявлении первичного ключа.
Я также часто использую этот запрос для просмотра текущих нарушений первичного ключа по таблице:
SELECT
DATABASE_NAME
,TABLE_OWNER
,TABLE_NAME
,COUNT(*) QUANTITY
FROM
NZ_DUPLICATE_PKS
WHERE
CURRENT_RECORD_INDICATOR = 'Y'
GROUP BY
1
,2
,3
ORDER BY
1
,2
,3;
Это суммирует все.Я надеюсь, что некоторые люди находят это полезным.Мы уже добились большого прогресса в этом подходе.На данный момент, вы можете быть удивлены, почему я пошел на все эти неприятности.Я терпеть не могу, что нарушения PK допускаются на наш склад, и я хотел комплексный подход к их устранению.Вышеуказанный процесс выполнялся ежедневно в нашей производственной среде в течение пары месяцев.У нас есть ~ 350 таблиц с объявленными первичными ключами, размером от 5 измерений строк до ~ 200 миллионов фактов строк при 10 ГБ.Для Netezza это довольно скромные затраты.Весь процесс занимает меньше 10 минут на нашем Mustang NPS 10050.