Как снизить стоимость этого запроса? - PullRequest
0 голосов
/ 25 марта 2019

У меня есть две таблицы, table1 и table2. table2 содержит разрешения для записей в table1, т.е. е. одна строка в table1 может иметь несколько соответствующих строк в table2.

Теперь мне нужно написать оператор SQL, который бы извлек эти записи table1, которые

  1. имеют определенный первичный ключ (table1.ID) и
  2. не имеет ни одного из указанных разрешений.

Я пришел с этим запросом:

SELECT table1.id
FROM TABLE1 table1
WHERE table1.ID IN (<ID_List>) AND
(<Excluded_permission_List>) NOT IN (
    Select PERMISSION_NAME
    from TABLE2 table2 
    where table2.perm_owner_id = table1.id
);

, где

  • <ID_List> - список всех первичных ключей таблицы1 для поиска, а
  • <Excluded_permission_List> список всех исключенных разрешений (т. Е. Если запись table1 имеет какое-либо из разрешений, содержащихся в <Excluded_permission_List>, она не должна появляться в результатах).

Пример: * 1 034 *

SELECT table1.id
FROM TABLE1 table1
WHERE table1.ID IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) AND
('SUPERUSER-1', 'MODERATOR-2') NOT IN (
    Select PERMISSION_NAME
    from TABLE2 table2 
    where table2.perm_owner_id = table1.id
);

Этот запрос должен возвращать те записи таблицы1, которые

  • имеют идентификаторы 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 и
  • не имеют ни разрешения SUPERUSER-1, ни MODERATOR-2.

Этот запрос работает, но согласно EXPLAIN PLAN стоимость составляет 38 (см. Ниже).

EXPLAIN PLAN output

Как можно снизить стоимость этого запроса?

1 Ответ

1 голос
/ 25 марта 2019

У вас есть коррелированный подзапрос в предложении Существует в качестве предиката, который выполняется для каждой отфильтрованной родительской строки. Попробуй это. CBO может переписать предикат для предотвращения объединения (хеш-соединение или вложенные циклы)

SELECT table1.id
FROM TABLE1 table1
WHERE table1.ID IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) AND
(('SUPERUSER-1', table1.id), ('MODERATOR-2', table1.id)) NOT IN (
    select table2.permission_name, table2.perm_owner_id
    from TABLE2 table2 
    where table2.perm_owner_id is not null and table2.permission_name is not null
);
...