优化复杂查询(使用分页)

时间:2017-07-24 07:22:58

标签: algorithm scala optimization slick akka-stream

假设某些数据库(PostgreSQL)中有N个表。每个表Ti都包含字段(time, label),其中time是某个数字(例如,长timestamp)。 label是一些文字。

N个条件。每个条件Ci都应用于特定表Ti。每个条件都可能很复杂(使用自己的子查询,也可以加入)。

我需要从条件中收集所有表T中的记录,并获取一个排序结果页面。此任务由SQLUNION 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-streamsslick-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]

它有效,但也许存在更有效的解决方案。如果你指出正确的方向,将不胜感激。

1 个答案:

答案 0 :(得分:0)

您是否可以在Slick中使用unionAll操作?

val streamT1 = Source.fromPublisher(db.stream(
      (Q1 unionAll Q2 unionAll Qn).sortBy(time) ))

Cf: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) ))