Как оптимизировать этот вложенный запрос SQL SELECT - PullRequest
0 голосов
/ 19 апреля 2019

У меня очень медленный запрос, который выглядит следующим образом:

SELECT  *
FROM    (
         SELECT ..., nn_key_fast(nachname) nnk, ...
         FROM   t1
           JOIN t2 ON
               ...
           JOIN t3 ON
               ...
           JOIN t4 ON
               ...
         WHERE  ...
         AND t4.POSTCODE='1234'
        )
WHERE  ... AND nnk LIKE "N%"

Теперь внутренний выбор занимает ~ 2 минуты.Если я удаляю последнее предложение WHERE (t4.POSTCODE), оно выполняется за ~ 4 сек.Результат без этого условия будет <1000 записей, поэтому очень маленький набор. </p>

Итак, я подумал: переместите это предложение во внешний SELECT, тогда оно будет применено только к результирующим <1000 записей.</p>

Но нет.Запрос занимает ровно столько времени, поэтому, чтобы быть понятным:

SELECT  *
FROM    (
         SELECT  .....
         FROM    t1
           JOIN  t2 ON
                 ...
           JOIN t3 ON
                 ...
           JOIN t4 ON
                 ...
         WHERE   ... 
        )
WHERE  ...
AND POSTCODE='1234'

занимает те же 2 минуты, что и первая версия.

Мне это кажется безумным.

Интуитивно это должно быть выполнено оптимизатором запросов следующим образом: создайте таблицу из внутреннего выбора, как показано в:

CREATE TABLE res_from_inner AS (
                                SELECT .....
                                FROM t1
                                  JOIN t2 ON
                                       ...
                                  JOIN t3 ON
                                       ...
                                  JOIN t4 ON
                                       ...
                                WHERE ... 
                               )

..., а затем выполните внешний выбор только для этой таблицы, например так:

SELECT  *
FROM    res_from_inner
WHERE   POSTCODE='1234'

И если я делаю это вручную, запрос CREATE TABLE занимает ~ 4 секунды, а второй SELECT принимает, как и ожидалось, <1 сек. </p>

Как это возможно, и что делать с этимэто?

Ответы [ 2 ]

1 голос
/ 19 апреля 2019

Я стараюсь держаться подальше от вложенных операторов выбора.В этом случае я бы использовал внутренний оператор select в качестве подзапроса, а затем выбрал из него то, что мне нужно.

с подзапросом as (select ... from ... join ... join ...присоединиться ... где)

выбрать * из подзапроса

- надеюсь, это поможет:]

1 голос
/ 19 апреля 2019

Вы должны посмотреть на планы выполнения, чтобы увидеть, что на самом деле происходит. Что-то меняется.

Одна вещь, которую вы можете попробовать - это CTE:

with s as (
      <subquery here>
     )
select s.*
from s
where . . .;

Oracle может автоматически это реализовать. Или вы можете дать подсказку:

with s as (
      select /*+ materialize */ . . .
      . . .
     )
select s.*
from s
where . . .;
...