如何解决如何克服Netezza缺乏唯一约束/参照完整性强制的问题?
| 似乎缺乏对强制执行两个基本约束(唯一键和外键)的支持,这是许多工时调试和故障排除困难问题的原因。最初的琐碎,易于修复的问题(重复行/主从表不一致)变得不为人知,在我们的应用程序甚至我们的硬件中(甚至与硬连接自连接),其增长和引发了复杂的边缘情况。可能会导致膨胀和存储耗尽)。 Netezza在我们的环境中有多种用途:生产,研究,质量保证和分期。当然,我们的ETL流程还不成熟,无法在所有这些情况下验证所有约束。 即使在生产中使用的最成熟的应用程序中(在ETL加载数据时对其进行验证),我们也会创建一系列表,每个表都是对其前身进行计算的结果。有时,数据完整性会一路破坏,而不是一开始就被破坏(由于错误的声明) 谁能推荐一种避免这些头痛的方法论/工具?解决方法
我们最初编写了一个存储过程来处理我们数据仓库中的这一件事。
尽管从理论上讲它是可行的,但对于在NZ上常见的大型表来说却有点慢(对于500M记录表,大约需要10分钟)。
我将在下面解释存储的proc,但是现在我想说的是我们目前甚至没有利用proc,因为我们的增量/ upsert加载明确地仅插入目标数据库中尚不存在的记录。 。 (对于upsert,我们基本上只是删除插入之前要插入的记录集中的所有记录)。
这有它自己的问题,尤其是因为NZ不喜欢删除,并且需要不断整理表以实际回收空间,更不用说我们的高手可能会通过删除旧记录而丢失历史列数据这一事实。之后就进行了更改(我们还有其他过程可以加载要跟踪的尺寸不断变化的尺寸。)
无论如何,约束存储过程看起来像:
check_constraints(\'table\',\'constraint_type\') returns boolean
并基本上循环通过:
select constraintname,contype,attname
from _v_relation_keydata
where relation = upper(p_table) order by constraintname,conseq;
要获得应比较的列。对于每个约束,然后运行类似:
select count(*)
from (
select distinct col1,col2,...
from p_table
where col1 is not null
and col2 is not null... );
并将该数字与
select count(*)
from p_table
where col1 is not null
and col2 is not null...;
如果它们不同,我们将引发一个例外。
,我知道有一个可以接受的答案,尽管我想提供一种替代方法。作为我目前的职位的新手,我不了解仓库中主键声明背后的所有业务决策。我开发了日志记录类型的方法来跟踪一段时间内重复行的删除工作。以下是此设计的主要功能:
始终保持最新状态,解决DDL / DML的不稳定问题
新建/删除表
新/更新的主键
新增/更新/删除的行
自填历史
随着时间的推移跟踪改进
为各级趋势分析提供依据
轻松查询目标表以进行研究
无需使用HAVING子句进行自我联接或查找键列
目前仅处理主键
可以轻松扩展以解决唯一性约束(_V_RELATION_KEYDATA中的CONTYPE = \'u \')
从Netezza的角度来看,这是需要的一切。在注明的地方,您将需要填补空白才能创建动态SQL。
首先,我创建了一个表,该表跟踪所有重复记录的数据库,表和内部rowid。
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申请中的行ID具有均匀的自然分布,因此在基于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,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};
在遍历所有表以为临时表设定种子之后,我将运行一系列查询,将数据库,所有者,表名和行ID视为一个缓慢变化的维度。该查询的结束日期是目标表中暂存表中不存在的记录:
UPDATE
NZ_DUPLICATE_PKS
SET
CURRENT_RECORD_INDICATOR = \'N\',LAST_UPDATE_TIMESTAMP = CURRENT_TIMESTAMP
WHERE
CURRENT_RECORD_INDICATOR = \'Y\'
AND
(
DATABASE_NAME,ROW_ID
)
NOT IN
(
SELECT
DATABASE_NAME,ROW_ID
FROM
STG_NZ_DUPLICATE_PKS
)
;
最后,将最新记录插入目标表:
INSERT
INTO
NZ_DUPLICATE_PKS
(
DATABASE_NAME,LAST_UPDATE_TIMESTAMP
)
SELECT
DATABASE_NAME,LAST_UPDATE_TIMESTAMP
FROM
STG_NZ_DUPLICATE_PKS
WHERE
(
DATABASE_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,COUNT(*) QUANTITY
FROM
NZ_DUPLICATE_PKS
WHERE
CURRENT_RECORD_INDICATOR = \'Y\'
GROUP BY
1,2,3
ORDER BY
1,3;
总结了一切。我希望有些人觉得它有用。我们已经在这种方法上取得了很大的进步。在这一点上,您可能想知道为什么我要去处理所有这些麻烦。我讨厌将违反PK的行为允许进入我们的仓库,我希望采用一种全面的方法来消除它们。以上过程每天在我们的生产环境中运行了几个月。我们有约350个表带有声明的主键,范围从5行尺寸到2亿行事实@ 10Gb。对于Netezza来说,这是一笔不大的支出。在我们的Mustang NPS 10050上,整个过程不到10分钟。
,为什么不添加一个列,该列是要对其施加约束的列的哈希值? NZ SQL扩展程序包具有哈希功能。如果您使用hash8(\'key \'),其中\'key \'是约束列值的隐式表示(广播到varchar),那么您可能会获得唯一的BIGINT值。我之所以说“可能”,是因为哈希冲突的机率是有限的。如果您需要更强的唯一性保证,则可以使用加密级别的\'hash()\'函数。
除非您确实有大量数据,否则hash8应该是更好的选择。因为它给出整数值,所以行比较只是简单的算术问题,因此比较快。因此,例如,您可以仅基于哈希值(只是一个整数比较)来更新或插入行。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。