Scala slick:在多个列上使用“ in”进行过滤

时间:2019-03-02 17:30:07

标签: scala slick slick-3.0

假设我具有以下表结构:

create table PEOPLE (
    ID integer not null primary key,
    NAME varchar(100) not null
);

create table CHILDREN (
    ID integer not null primary key,
    PARENT_ID_1 integer not null references PERSON (id),
    PARENT_ID_2 integer not null references PERSON (id)
);

,我想生成一个父母双方的姓名列表。光滑的我可以这样写:

for {
  parent <- people
  child  <- children if {
    parent.id === child.parent_id_1 ||
    parent.id === child.parent_id_2
  }
} yield {
  parent.name
}

并生成预期的SQL:

select p.name
from people p, children c
where p.id = c.parent_id_1 or p.id = c.parent_id_2

但是,这并不是最佳选择:表达式的OR部分可能会导致某些DBMS的性能异常降低,即使有索引,最终也会进行全表扫描以加入p.id在那里(例如,参见this bug report for H2)。普遍的问题是查询计划者无法知道单独执行OR的每一面并将结果重新结合在一起还是执行全表扫描[2]更快。

我想生成看起来像这样的SQL,然后可以按预期使用(主键)索引:

select p.name
from people p, children c
where p.id in (c.parent_id_1, c.parent_id_2)

我的问题是:如何才能做到这一点?现有方法似乎没有提供一种方法:

我想写的是这样的:

for {
  parent <- people
  child  <- children
  if parent.id in (child.parent_id_1, child.parent_id_2)
} yield {
  p.name
}

但是现在不可能。

[1]我的实际设计要比这复杂一些,但是归结为相同的问题。

[2]一些DBMS do 具有针对某些简单情况的优化,例如OR-expansion in Oracle

1 个答案:

答案 0 :(得分:0)

结果证明这是当前不可能的(如光滑的3.2.3),因此我raised an issue on github并提交了添加此功能的请求。