SQL - 优化批量插入和大型连接的性能?

时间:2009-08-05 15:36:32

标签: sql postgresql

我正在将日志文件的ETL用于PostgreSQL数据库,并希望了解用于优化将数据加载到简单星型模式中的性能的各种方法。

要将问题放在上下文中,以下是我目前所做工作的概述:

  1. 删除所有外键并且唯一 约束
  2. 导入数据(约1亿条记录)
  3. 重新创建约束并在事实表上运行analyze。
  4. 通过从文件加载来导入数据。对于每个文件:

    1)使用COPY(PostgreSQL批量上传工具)将数据加载到临时表中

    2)使用每个插入对任何新数据更新每个9维表,例如:

    INSERT INTO host (name)
    SELECT DISTINCT host_name FROM temp_table
    EXCEPT
    SELECT name FROM host;
    ANALYZE host;
    

    分析是在INSERT结束时运行的,其目的是在数千万次更新过程中保持统计数据是最新的(这是可取的还是必要的?至少它似乎没有显着降低性能)

    3)然后使用unholy 9-way join更新事实表:

    INSERT INTO event (time, status, fk_host, fk_etype, ... ) 
    SELECT t.time, t.status, host.id, etype.id ... 
    FROM temp_table as t 
    JOIN host ON t.host_name = host.name
    JOIN url ON t.etype = etype.name
    ... and 7 more joins, one for each dimension table
    

    我有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我已经尝试了几种不同的方法来尝试规范化来自源的数据,通常我发现你现在使用的方法是我的选择。它易于遵循和微小的变化保持轻微。尝试在阶段2期间从其中一个维度表返回生成的ID只会使事情变得复杂,并且通常会生成太多的小查询,以便对大型数据集有效。 Postgres在现代版本中使用“unholy join”非常有效,使用“select distinct除了select”对我来说效果很好。其他人可能知道的更好,但我发现你当前的方法是我的方法。

答案 1 :(得分:0)

在第2阶段,您知道您要插入数据的每个维度的主键(在您插入数据后),但是将此信息丢弃并在第3阶段使用“邪恶的”9向联接重新发现它。

相反,我建议创建一个sproc插入到事实表中;例如insertXXXFact(...),根据命名约定getOrInsertXXXDim调用其他一些sprocs(每个维度一个),其中 XXX 是相关维度。这些sproc中的每一个都将查找或插入给定维度的新行(从而确保参照完整性),并应返回事实表应引用的维度的主键。这将显着减少您在第3阶段需要完成的工作,现在已减少为insert into XXXFact values (DimPKey1, DimPKey2, ... etc.)

形式的调用

我们在getOrInsertXXX sprocs中采用的方法是,如果一个虚拟值不可用,则插入一个虚拟值,并在稍后使用单独的清理过程来识别和丰富这些值。