2009-08-05 79 views
3

我正在做日志文件的ETL到PostgreSQL数据库,并且想了解更多关于用于优化将数据加载到简单的星型模式中的性能的各种方法。SQL - 优化批量插入和大型连接的性能?

摆在上下文中的问题,下面是我目前做一个概述:

  1. 删除所有外键和唯一 约束
  2. 导入数据(约100万条记录)
  3. 回复 - 创建约束并在事实表上运行分析。

导入数据是通过从文件加载完成的。对于每一个文件:

1)利用COPY从数据加载到临时表(PostgreSQL的大量上传工具)

2)更新每个9代维表的使用的插入对于每个这样的任何新的数据如:

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

的Analyze在拥有超过千万的更新的过程中保持统计最新(的想法INSERT结束时运行这是可取的或必要的最低它不?似乎会显着降低性能)。

3)事实表,然后用邪恶的9路更新加入:

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 

是否有更好的方法我俯瞰?

回答

1

我尝试了几种不同的方法来试图规范化来自源的数据传入,因此通常我已经找到了您现在使用的方法来作为我的选择。它容易遵循和轻微的变化保持轻微。尝试在阶段2期间从维度表中返回生成的标识仅仅是复杂的事情,并且通常会生成太多的小型查询以便对大型数据集有效。在现代版本中,Postgres应该非常有效地使用“unholy join”,并且使用“选择不同的除了select”对我很好。其他人可能会更好地了解,但我发现你现在的方法是我的推荐方法。

0

在第2阶段你知道你将数据插入到(你插入后),每个维度的主键,但你扔掉该信息,并重新发现它在第3阶段您“邪恶”的9路加入。

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

我们在getOrInsertXXX sprocs中采用的方法是如果没有可用的值插入虚拟值并有一个单独的清理流程,以便稍后识别和丰富这些值。

+1

我原则上同意,但是当我尝试这种方法时,我发现它平均慢了50%。它看起来像维度表的缓存结合做大量操作(而不是单独的选择/插入)更快。 – Rob 2009-08-05 19:19:20

+1

@Rob:这很有趣,因为它是一种过去为我工作的方法。顺便说一句,我不能相信这个答案没有任何评论downvoted! – Adamski 2009-08-12 09:52:34