Sql Teradata中具有一对一关系的表的插入策略

Sql Teradata中具有一对一关系的表的插入策略,sql,teradata,etl,Sql,Teradata,Etl,在源自Teradata行业模型的数据模型中,我们观察到一种常见模式,即逻辑数据模型中的超类和子类关系转换为父表和子表之间的一对一关系 我知道您可以向上或向下滚动属性,以一个表结束,但我们总体上不使用此选项。最后,我们有一个这样的模型: 其中城市Id引用地理区域Id 我正在努力寻找一个好的策略来加载这些表中的记录 选项1:我可以选择MaxGeographic Area Id并计算批插入的下一个Id,然后在City表中重用它们 选项2:我可以在地理区域表中使用标识列,并在插入每条记录后检索它,以便将

在源自Teradata行业模型的数据模型中,我们观察到一种常见模式,即逻辑数据模型中的超类和子类关系转换为父表和子表之间的一对一关系

我知道您可以向上或向下滚动属性,以一个表结束,但我们总体上不使用此选项。最后,我们有一个这样的模型:

其中城市Id引用地理区域Id

我正在努力寻找一个好的策略来加载这些表中的记录

选项1:我可以选择MaxGeographic Area Id并计算批插入的下一个Id,然后在City表中重用它们

选项2:我可以在地理区域表中使用标识列,并在插入每条记录后检索它,以便将其用于城市表

还有其他选择吗

我需要从性能、可靠性和维护方面评估解决方案

如有任何意见,将不胜感激

亲切问候,


Paul

当您说将记录加载到这些表中时,您是指一次性数据迁移还是为新的地理区域/城市创建记录的功能

如果您正在寻找代理项,并且对ID值中的间隙没有问题,那么请使用IDENTITY列并指定NO CYCLE子句,这样它就不会重复任何数字。然后只需为值传递NULL,并让TD处理它

如果您确实需要顺序ID,那么您可以只维护一个单独的NextId表,并使用它来生成ID值。这是最灵活的方法,可以使您更轻松地管理批处理操作。它需要更多的代码/维护,但比在数据表上执行MAX+1来获取下一个ID值更有效。基本思路如下:

开始交易

从查找表中获取下一个ID 使用该值为下一个记录生成新的ID值 创建新记录 更新查找表中的下一个ID值,并根据新插入的行将其递增。执行INSERT/MERGE语句后,可以通过将该值直接存储在ACTIVITY_COUNT value变量中来捕获该值 确保在事务开始时锁定查找表,以便在事务完成之前不能修改它 结束交易

以下是Postgres的一个例子,您可以适应TD:

CREATE TABLE NextId (
    IDType VARCHAR(50) NOT NULL,
    NextValue INTEGER NOT NULL,
    PRIMARY KEY (IDType)
);

INSERT INTO Users(UserId, UserType)
SELECT 
    COALESCE(
        src.UserId, -- Use UserId if provided (i.e. update existing user)
        ROW_NUMBER() OVER(ORDER BY CASE WHEN src.UserId IS NULL THEN 0 ELSE 1 END ASC) + 
        (id.NextValue - 1) -- Use newly generated UserId (i.e. create new user)
    )
    AS UserIdFinal,
    src.UserType
FROM (
    -- Bulk Upsert (get source rows from JSON parameter)
    SELECT src.FirstName, src.UserId, src.UserType
    FROM JSONB_TO_RECORDSET(pUserDataJSON->'users') AS src(FirstName VARCHAR(100), UserId INTEGER, UserType CHAR(1))
) src
CROSS JOIN ( 
    -- Get next ID value to use
    SELECT NextValue
    FROM NextId 
    WHERE IdType = 'User'
    FOR UPDATE -- Use "Update" row-lock so it is not read by any other queries also using "Update" row-lock
) id
ON CONFLICT(UserId) DO UPDATE SET
UserType = EXCLUDED.UserType;

-- Increment UserId value
UPDATE NextId
SET NextValue = NextValue + COALESCE(NewUserCount,0)
WHERE IdType = 'User'
;   
只需将locking语句更改为Teradata syntax LOCK TABLE NextId FOR WRITE,并在插入/合并后添加一个ACTIVITY_COUNT变量,以捕获受影响的行。这假定您在存储过程中执行所有这些操作


让我知道情况如何…

不要自己计算ID。始终使用自动递增搜索web以进行过早优化使用自动递增将是我的首选,但一些Teradata用户报告了诸如标识值不是按顺序生成的问题,但我想我可以在执行插入后获得记录Id。关于过早优化,如果我提前知道,如果一个操作不能成批执行,那么它很快就会成为性能瓶颈。从我的观点来看,成批执行的选项是一种需求,而不是过早的优化。Teradata上的标识值不会是连续的,但这应该是完全无关的。这不是你想要的最小值、最大值等。它只是一个代理键。嗨,谢谢你的回答。您的解决方案是我已经找到的解决方案的一种组合。为什么使用Identity列而不是在应用程序中生成ID更好,为什么为NextValue维护第二个表而不是使用SQL查询动态计算它更好?我测试了你的解决方案,效果很好。现在,我要么将其转换为Talend包,要么创建一个存储过程并从Talend调用它。不客气。使用标识列的优点是您不必维护(即自己检索/增加值)、担心唯一性或额外的表锁。这更容易。如果您想自己管理ID值,这实际上取决于您的偏好。如果它是一个小的应用程序,性能不是一个巨大的优先级,等等……那么您可以根据需要动态计算ID。保留NextId表的原因是为了避免每次插入时进行聚合时的性能损失。要获取下一个ID,需要一行UPI连接…非常快。