【性能优化】4.4 [遍历技术] 数据库并行加载
4.4 数据库并行加载
有时我们需要从数据库中读出数据进行复杂运算,常常会发现数据库负载并不重的时候,读出数据的时间却很长。这主要是由于数据库的访问接口性能较差导致的,使用并行可以有效地缓解这个问题。
A | B | |
1 | fork to(4) | =connect(…) |
2 | =range(MinID,MaxID+1,A1:4) | |
3 | =B1.query("select * from T where id>=? and id<?,B2(1),B2(2)) | |
4 | >B1.close() | |
5 | =A1.conj() |
这段代码将并行取出 T 表中 id 值在 MinID 和 MaxID 范围之间的记录。将条件区间拆分成多段,每个线程取其中一段。注意数据库需要在每个线程内单独连接,否则数据库会强制同一个连接的请求串行执行,并行逻辑就无法实现了。
数据库没有接口实现分段拆分,只能使用 where 来拆分,可以根据对数据特征的了解使用更合理的拆分方案。where 计算会占用数据库资源,并行取数只能在数据库资源不紧张时应用(取数慢是由于接口慢而不是数据库计算慢),太复杂的 where 计算也会造成并行取数的效果变差。
如果取出数据量大要使用数据库游标,那要在每个线程内处理读出来的数据,才能起到并行的效果,不能在线程中返回延迟游标而没有实质计算。
A | B | |
1 | fork to(4) | =connect(…) |
2 | =range(MinID,MaxID+1,A1:4) | |
3 | =B1.cursor("select * from T where id>=? and id<?,B2(1),B2(2)) | |
4 | =B3.groups(…) | |
5 | =A1.conj().groups(…) |
使用多个不同 SQL 取数时也可以使用并行方案:
A | B | |
1 | =["select …","select…",…] | |
2 | fork A1 | =connect(…) |
3 | =B2.query(A2) | |
4 | >B2.close() | |
多个 SQL 时可以使用更大的一些并行线程数,不同 SQL 执行速度不同,即使物理上没有更多的线程数,也能起到平衡负载的作用。有线程分配到可较快执行的 SQL 时,可以执行更多任务,以避免线程等待。