【性能优化】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 时,可以执行更多任务,以避免线程等待。