2010-03-11 41 views
2

我需要从一个表中选择数据并将其插入到另一个表中。目前SQL看起来是这样的:一次只选择一组特定的行

INSERT INTO A (x, y, z) 
    SELECT x, y, z 
    FROM B b 
    WHERE ... 

但是,SELECT是巨大的,导致超过200万行,我们认为它占用了太多的内存。在这种情况下,Informix在查询运行时会耗尽虚拟内存。

我该如何去选择和插入一组行(如2000)?鉴于我不认为有任何行ID等

+0

尝试'FIRST'; LIMIT是支持10+的同义词:http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.docnotes.doc/uc3/ids_sqlt_docnotes_10.0.html – 2010-03-11 22:23:28

+0

是的,并且将它与'skip'结合起来就可以遍历循环中的整个集合。(*如果知道总行数*) – 2010-03-11 22:29:19

+0

如果表B发生了变化,那么不要冒着跳过的风险你还没有复制过的行?我知道我没有提到表B可以改变,在我的情况下它可能不会改变,但我只是在这里大声思考。 – rouble 2010-03-11 22:35:08

回答

3

你可以从表做SELECT FIRST n *。其中n是所需的行数,例如2000.另外,在WHERE子句中,执行一个嵌入式选择,用于检查要插入的表是否已存在的行。因此,下次语句运行时,不会包含已插入的数据。

+0

这听起来不错。你将如何编写一个循环直到select返回没有行的选择循环? – rouble 2010-03-11 22:46:32

+0

使用NOT EXISTS函数确保您插入的行不存在于新表中。 – northpole 2010-03-11 23:07:27

0

我认为你有一些脚本,这是从执行?只要您对从嵌套选择返回的值进行排序,您就可以循环并进行限制。这是一些伪代码。

total = SELECT COUNT(x) FROM B WHERE ... 
while (total > 0) 
    INSERT INTO A (x, y, z) SELECT x, y, z FROM B b WHERE ... ORDER BY x LIMIT 2000 
    total = total - 2000 
end 
0

我几乎可以肯定的是IDS只允许你使用其中数据被返回给客户端第一条,就是要避免,如果在所有可能的东西。

你说你得到一个内存不足的错误(而不是说,长事务中止错误)?你看过你的服务器的配置,以确保它有合理的内存量吗?

它部分取决于您的数据集有多大以及约束条件是什么 - 您为什么要跨表执行负载。但我通常会确定一种将数据分区为可加载子集并在循环中顺序运行这些子程序的方法。例如,如果序列号在1和10,000,000之间,我可以运行循环十次,条件是序列号为AND seqnum >= 0 AND seqnum < 1000000' and then,序列号= 1000000和序列号< 2000000'等等。优选地,通过变量替代范围。

这有点麻烦,你希望在范围大小方面保守一些(更小的分区而不是更小的分区 - 以减少内存不足的风险)。


略高于简化。例如,一个存储过程将不得不算作'客户',并且存储过程中的通信成本比去往真正客户端的成本要少很多。