0

我正在处理相对较大的数据集;~200GB。数据来自通过脚本导入 SQL 的文本文件。它们被批量复制到一个临时表中,规范化的表等待接收数据。

我的问题来自这样一个事实,即我主要是一名脚本编写者,所以我的逻辑是遍历每一行并对每行进行单独检查以将数据放在需要去的地方,但我在 SO 上阅读了另一篇文章说这真的是错误的对于 SQL。

所以我的问题是,如果我有一个临时表(31 列)要在另外 5 个之间进行标准化,那么最好的方法是什么?

表关系如下:

系统 - 包含机器信息(例如名称、域等)的表

文件 - 文件信息(例如名称、大小、目录等)

SystemFile - 多对多系统<->文件关系表。

元数据 - 文件元数据(语言等) - 与文件主键有外键关系

DigitalSignature - 文件数字签名状态 - 与文件主键有外键关系

谢谢

4

1 回答 1

2

没有任何链接,在 ssis 等方面没有足够的经验来提供平衡的观点。但是在执行您正在谈论的任务时,我的正常流程将是(通用,简单版本):

1.查看规范化数据集并考虑导入数据中依赖最少的组件(例如,在订单项目之前创建的订单标题)

2.create查询选择我将拥有的数据..这些通常有这种形式:

 select
    t.x,t.y,t.z
 from
    temp_table as t
    left outer join normalise_table as n
        on t.x=n.x
        and t.y=n.y
        and t.z=n.z
 where
    n.x is null

其中 temp_table 可能有很多列,但这三个代表我想首先添加的任何规范化块,左外连接和 null 确保我只得到新值 - 如果合并是相同的

验证我得到了很好的信息,并且我只得到了我想要的新行。通常,您必须在临时数据上使用 group bys 或 distincts 来获取准确的数据以进行插入.. 例如:

 select
    t.x,t.y,t.z
 from
    (select 
        distinct x,y,z
     from    
         temp_table ) as t
    left outer join normalise_table as n
        on t.x=n.x
        and t.y=n.y
        and t.z=n.z
 where
    n.x is null

3.将该选择包装在插入中:

  insert into 
     normalise_table (x,y,z)
  select
    t.x,t.y,t.z
 from
    (select 
        distinct x,y,z
     from    
         temp_table ) as t
    left outer join normalise_table as n
        on t.x=n.x
        and t.y=n.y
        and t.z=n.z
 where
    n.x is null

通过这种方式,您正在插入数据集。程序部分正在为要插入的每个数据集执行此操作,但通常您不会遍历行。

顺便说一句,T-SQL 有一个合并命令,用于您何时可能有或可能没有目标表中的数据(以及如果您想删除临时表中缺少的键)

http://msdn.microsoft.com/en-us/library/bb510625.aspx

关于外键的一些评论- 这些往往更具体到具体情况:

你能识别没有主键的关系吗?这是最容易处理的情况..

想象一下,我已将我的 xyz 对象插入到规范化表中,但它在另一个表中有 100 个子行(abc's)(每个孩子也可能有 100 个孩子......这意味着一个 xyz 的非规范化数据中有 10000 行)

您必须先通过验证,但您的最终查询可能类似于:

insert into 
    normalise_table_2 (parentID,a,b,c)
select
    n.id,t.a,t.b,t.c
from
   (select 
       distinct x,y,z,a,b,c
   from    
       temp_table ) as t
   inner join join normalise_table as n
       on t.x=n.x
       and t.y=n.y
       and t.z=n.z
   left outer join normalise_table_2 as n2
       on n.id = n2.parentID
       and t.a = n2.a
       and t.b = n2.b
       and t.c = n2.c
where
    n2.a is null

或者更易读的方式:

insert into normalise_table_2 (parentID,a,b,c)
select
    *
from (
    select distinct
        n.id,t.a,t.b,t.c
    from
        normalise_table as n
        inner join temp_table as t
            on t.x = n.x
            and t.y = n.y
            and t.z = n.z
        left outer join normalise_table_2 as n2
            on t.a = n2.a
            and t.b = n2.b
            and t.c = n2.c
            and n2.parentID = n.id
        where
            n2.id is null
    ) as x        

如果您在识别没有 id 的行时遇到问题,请考虑以下几点

  1. 我经常为非规范化/导入数据中的每一行提供一个唯一的 ID,这样可以更轻松地跟踪已完成和未完成的操作。更不用说以其他方式得到回报(例如,当源数据有空白时,如果它们与上面的行相同)
  2. 我创建了临时表来跟踪这样的关系。
    • 有时(特别是对于不太一致的数据)这些不是临时表,因为它们可以在事后用于分析导入和未导入的内容(以及它的去向),有时我有一个评论列,更新查询填充任何有关与该行的导入有关的异常的详细信息。
  3. 有时你很幸运,目标中有某种源或 oldId 字段可用于链接非规范化数据和规范化版本(对于系统迁移类型的任务尤其如此,因为人们经常希望能够查看旧系统中的项目)。有时这可能很奇怪和美妙 - 例如使用更新或创建字段寻找执行此特定过程的特殊帐户(尽管我不会特别推荐)
  4. 有时以某种方式更新源表是有意义的..例如在那里替换标识符
  5. 有时,您提出了用于导入的 ID 范围或类似内容,并且您打破了关于生成 ID 的位置以及您的导入过程创建 ID 的常规规则。
    • 这通常意味着在执行导入时关闭对目标系统的所有其他访问。可能听起来很疯狂,但有时这是需要大量准备的非常复杂的上传的最佳方式

但是通常当您考虑它时,您可以添加数据并避免此问题,因为您将始终能够识别正确的数据。我已经使用上述技术让我的生活更轻松,但我不确定我是否曾经使用过它们。

我能想到的唯一例外是在我必须使用的系统之外生成 ID,但这是为了使 ID 在多个试验负载和最终生产负载之间保持一致。此外,数据来自许多来源,许多人都在研究它,这让他们可以控制自己的 ID 变得更轻松——但它确实带来了其他问题;)。

通常,我会尝试不理会源数据,并确保如果您重新运行任何脚本,它们将不会产生任何影响。这使得整个系统更加健壮,并且让每个人都更有信心,因为您可以重新导入相同的数据或具有一些相同数据的文件并再次运行所有内容,并且没有任何中断。

请注意,我没有测试任何这些查询,只是将它们从我的头顶上写下来,如果它们不完全准确,我很抱歉。

于 2013-09-23T20:51:23.390 回答