假设某个数据库(PostgreSQL(中有N
表。每个表Ti
都包含字段(time, label)
,其中time
是某个数字(例如长timestamp
(。label
是一些文本。
有N
条件。每个条件Ci
都应用于特定的表Ti
。每个条件都可能很复杂(使用自己的子查询,也使用连接(。
我需要从所有T
有条件的表中收集记录,并获得一页排序结果。此任务由SQL
和UNION ALL
解决。以下伪示例说明了获取某些页面:
(SELECT time, label FROM T1 WHERE C1
UNION ALL
SELECT time, label FROM T2 WHERE C2
UNION ALL
...
SELECT time, label FROM Tn WHERE Cn)
ORDER BY time LIMIT = x OFFSET = y
DISTINCT
如果条件C
很复杂并且表包含大量记录,则上述查询非常庞大且缓慢。 我想将这个复杂的查询拆分为子查询,其中每个子查询Qi
都应用于相应的表Ti
。在这种情况下,每个子查询的执行速度更快,但与联合结果相关的问题,对分页进行排序
。为此,我将使用akka-streams
和slick-streaming
.以下伪代码演示了如何获取两个表的某些页面:
val streamT1 = Source.fromPublisher(db.stream(Q1.sortBy(time)))
val streamT2 = Source.fromPublisher(db.stream(Q2.sortBy(time)))
val pageContent = streamT1.mergeSorted(streamT2)
.grouped(pageSize).drop(pageNumber)
.runWith(Sink.headOption)
下面的示例说明了两个表的分页:
val srcT1 = Source(
(0, "A_a"),
(1, "A_b"),
(2, "A_c"),
(5, "A_d"),
(7, "A_e"),
(8, "A_f"),
(9, "A_g"),
(10, "A_h"),
(11, "A_i"),
(15, "A_j"),
(16, "A_k"),
(17, "A_l"),
(20, "A_m"),
...
)
val srcT2 = Source(
(3, "B_d"),
(12, "B_e"),
(18, "B_f"),
...
)
上述集合的时间线图如下:
0 1 2 5 7 8 9 10 11 15 16 17 20
| | | | | | | | | | | | |
A_a---A_b---A_c---------------A_d---------A_e---A_f---A_g---A_h---A_i---------------------A_j---A_k---A_l---------------A_m--->
3 12 18
| | |
------------------B_d---------------------------------------------------B_e---------------------------------B_f--------------->
page-size=4
页面并按time
排序:
[A_a,A_b,A_c,B_d] [A_d,A_e,A_f,A_g] [A_h,A_i,B_e,A_j] [A_k,A_l,B_f,A_m]
它有效,但也许存在更有效的解决方案。如果您指出正确的方向,将不胜感激。
你不能简单地使用 Slick 中的unionAll
操作吗?
val streamT1 = Source.fromPublisher(db.stream(
(Q1 unionAll Q2 unionAll Qn).sortBy(time) ))
参考:http://slick.lightbend.com/doc/3.0.0/queries.html#unions
另外,最好也直接在 Slick 中使用 drop((/take((:
val streamT1 = Source.fromPublisher(db.stream(
(Q1 unionAll Q2 unionAll Qn)
.sortBy(time)
.drop(pageSize*pageNumber).take(pageSize) ))