Scala Slick: фильтр с использованием «в» на нескольких столбцах - PullRequest
0 голосов
/ 02 марта 2019

Предположим, у меня есть следующая структура таблицы:

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 может вызватьужасно низкая производительность в некоторых СУБД, которые заканчивают тем, что выполняют полные таблицы, чтобы присоединиться к p.id, даже если там есть индекс (см., например, этот отчет об ошибках для H2 ).Общая проблема заключается в том, что планировщик запросов не может знать, быстрее ли выполнить каждую сторону OR по отдельности и объединить результаты вместе или просто выполнить полное сканирование таблицы [2].

IХотелось бы генерировать SQL, который выглядит примерно так, который затем может использовать индекс (первичный ключ), как и ожидалось:

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

Мой вопрос: как я могу сделать это впятно?Существующие методы, кажется, не предлагают пути:

  • ColumnExtensionMethods.in принимает Query в качестве параметра, но у меня нет Query У меня есть номер или Rep[Long] для каждого из моих столбцов идентификаторов

  • ColumnExtensionMethods.inSet для привязки существующих (известных) литеральных массивов, а не для присоединения кнаборы столбцов

Я хотел бы написать что-то вроде этого:

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

, но сейчас это невозможно.

[1] Мой настоящий дизайн немного сложнее, чем этот, но он сводится к той же проблеме.

[2] Некоторые СУБД do имеют эту оптимизацию для простых случаев,например, ИЛИ-расширение в Oracle .

1 Ответ

0 голосов
/ 04 марта 2019

Оказывается, в настоящее время это невозможно (как на версии 3.2.3), поэтому я поднял проблему на github и отправил запрос на извлечение, чтобы добавить эту функциональность.

...