- 论坛徽章:
- 0
|
呵呵, 最近刚好遇到一个类似的问题, 是一组海量数据,
主要字段有两个: ID1和ID2, 其中ID1为主键, 而ID2也要求不能重复(即候补主键)
表中有数据七十万, 更新操作通过CSV文件做批量处理, 文件一般在二十万件左右
处理时, 要对文件中的每一条数据进行检查, 如果表中有相同的ID1和ID2则更新数据, 如果表中没有ID1和ID2则追加, 如果表中的ID1和ID2只有一个和文件中相同则将该记录写如错误记录表, 不对原表做更新,
为了提高处理效率, 偶将文件中的二十万条数据先直接存进临时表, 于是问题就变成了对两个表的处理, 直接的想法是从临时表中取出一条数据, 和目标表做比较, 这种做法需要六个小时(双3.06G CPU 4G内存), 因此考虑做优化, 通过对目标表中的ID做唯一制约, 将处理时间缩短到30分, 但仍然不能接受, 于是考虑不使用游标来完成的方法
首先, 要去掉临时表中关系有错误的记录
SELECT * FROM TEMP T
WHERE EXISTS(SELECT NULL FROM TEMP WHERE
TEMP.ID1= T.ID1 AND TEMP.ID2<>T.ID2)
然后, 去掉临时表中和目标表的关系有错误的记录
SELECT * FROM TEMP
WHERE EXISTS(SELECT NULL FROM TARGET WHERE
TEMP.ID1= TARGET.ID1 AND TARGE.ID2<>TARGET.ID2)
对目标表做追加(只追加主键然后做更新, 否则还要判断临时表中键值相同的记录)
SELECT DISTINCT ID1, ID2 FROM TEMP
WHERE EXISTS(SELECT NULL FROM TARGET WHERE
TEMP.ID1= TARGET.ID1)
更新目标表(这里用到了PGSQL的语法)
UPDATE TARGET
SET TARGET.* = TEMP.*
FROM TEMP
WHERE TARGET.ID1=TEMP.ID1
这样做的结果和使用游标的差不多, 甚至还要长一些, 经分析, 主要时间都花在第一个SQL文上了,
这是很麻烦的一件事, 临时表上不方便建立索性之类的东西, 因为它的主要作用是暂存数据并利用它对海量数据进行检查,
于是考虑使用下面的SQL文(看上去怪怪的, 呵呵)
DELETE TEMP
WHERE (ID2, ID1) IN
(SELECT DISTINCT ID2, ID1 FROM TEMP
MINUS
SELECT ID2, MIN(ID1) FROM TEMP GROUP BY ID2)
上面这段SQL文把有问题的数据保留了一条, 由于没有破坏要求的关系, 因此可以接受, 同时它把根据ID1来检查ID2的工作留给了下面的处理,
经过这样的改造, 完成全部处理所需时间只有六秒钟, 嘿嘿
 |
|