【问题标题】:Insert strategy for tables with one-to-one relationships in TeradataTeradata 中具有一对一关系的表的插入策略
【发布时间】:2018-06-27 10:36:21
【问题描述】:

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

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

城市 ID 引用地理区域 ID。

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

选项 1:我可以选择 max(Geographical Area Id) 并计算批量插入的下一个 Id,并将它们重用于 City Table。

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

还有其他选择吗?

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

任何评论将不胜感激。

亲切的问候,

保罗

【问题讨论】:

  • 永远不要自己计算 ID。始终使用自动增量
  • 在网上搜索premature optimisation
  • 使用自动增量将是我的首选,但一些 Teradata 用户报告了身份值未按顺序生成等问题,但我想我可以在执行插入后获取记录 ID。
  • 关于过早优化,如果我提前知道,一个操作不能批量执行,迟早会成为性能瓶颈。从我的角度来看,分批执行某事的选项是一种需求,而不是过早的优化。
  • Teradata 上的身份值不会是连续的,但这应该是完全不相关的。这不是您想要最小、最大等的东西。它只是一个代理键。

标签: sql teradata etl


【解决方案1】:

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

如果您正在寻找一个代理键并且您的 ID 值有空缺,则可以使用 IDENTITY 列并指定 NO CYCLE 子句,这样它就不会重复任何数字。然后只需将值传递为 NULL 并让 TD 处理它。

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

开始交易

  • 从查找表中获取“下一个”ID
  • 使用该值为您的下一条记录生成新的 ID 值
  • 创建新记录
  • 更新查找表中的“下一个”ID 值并将其增加 # 行新插入(您可以通过在执行 INSERT/MERGE 语句后直接将值存储在 ACTIVITY_COUNT 值变量中来捕获这一点)
  • 确保在事务开始时锁定查找表,以便在事务完成之前无法修改它

结束交易

这是 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'
;   

只需将锁定语句更改为 Teradata 语法 (LOCK TABLE NextId FOR WRITE) 并在 INSERT/MERGE 之后添加一个 ACTIVITY_COUNT 变量以捕获受影响的 # 行。这假设您在存储过程中执行所有这些操作。

告诉我进展如何...

【讨论】:

  • 您好,感谢您的回答。您的解决方案是我想出的解决方案的一种组合。为什么使用标识列而不是使用应用程序生成 Id 更好,为什么为“NextValue”维护第二个表而不是使用 SQL 查询动态计算它更好?我测试了您的解决方案的各个部分并且它有效。现在我必须将其转换为 Talend 包或创建存储过程并从 Talend 调用它。
  • 不客气。使用 IDENTITY 列的优点是您不必自己维护(即检索/递增)值,不必担心唯一性或额外的表锁。这更容易。如果您想自己管理 ID 值,这实际上取决于您的偏好。如果它是一个小型应用程序,性能不是一个很大的优先级,等等......那么你可以根据需要动态计算 ID。保留“NextId”表的原因是为了避免每次要插入时进行聚合对性能的影响。要获取您的下一个 ID,它是单行 UPI 连接...非常快。
猜你喜欢
  • 2018-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-12
  • 1970-01-01
  • 2020-08-07
  • 2016-10-15
相关资源
最近更新 更多