Каков порядок выполнения функции в SQL-запросе? - PullRequest
0 голосов
/ 26 сентября 2018

Если я создаю свою собственную функцию "myfunction" и этот запрос:

select
myfunction(parameters)
from
mytable
where
a and b and c and d

, если mytable имеет 1 миллион строк, но после моего, где у меня есть только 100 строк.Когда я выполнил этот запрос, моя функция будет выполнена для 100 или 1 миллиона строк?

и что в этом случае произойдет?

select
myfunction(parameters)
from
mytable
where
a and b and c and d and myfunction(parameters) == e

Ответы [ 4 ]

0 голосов
/ 26 сентября 2018

Во втором запросе Где предложение всегда будет выполнено 1 000 000 раз, однако его можно пропустить, если предыдущее условие отменит его выполнение в оптимизаторе, например, в следующем примере myfunction не будет выполняться вообще.

select *
from mytable
where a and b and c and d and 1=0 and myfunction(parameters) == e

Это происходит потому, что оптимизатор обнаруживает, что достигнуто «ложное» условие, поэтому нет необходимости выполнять any другое условие.

--- Первый запрос ---

select myfunction(parameters)
from mytable
where a and b and c and d

Моя функция будетвыполняется после вашего предложения where, поэтому, если ваш запрос возвращает только 100 записей, он будет выполнен 100 раз.

--- Второй запрос ---

select myfunction(parameters)
from mytable
where a and b and c and d and myfunction(parameters) == e

first myfunction будет выполняться два раза по одному в вашем предложении select , а также в вашем предложении where ,так что если ваш запрос возвращает только 100 записей, он будет выполнен 100 раз.но для вашего второго myfuntion он будет выполнен 1 миллион раз .

Лучший способ избежать этого 1 миллион выполнение функции в oracle это МАТЕРИАЛИЗАЦИЯ подсказка и С запросследующий запрос должен возвращать те же результаты, что и ваш второй запрос:

with hundred_records as (
    select /*+ MATERIALIZE */ myfunction(parameters) fn_result, mytable.*
    from mytable
    where a and b and c and d
)
select *
from mytable
where fn_result = e

Однако я настоятельно рекомендую добавить столбец внутри mytable для хранения myfunction В результате вы избавите себя от многих проблем с производительностью, делая это.Вам придется обновлять этот столбец каждый раз, когда вы знаете, что "параметры" изменились.

0 голосов
/ 26 сентября 2018

В первом примере это будет выполнено только 100 раз.Вы можете проверить это, добавив отладочный вызов в функцию:

create table mytable (a, b) as select mod(level, 10), level from dual connect by level <= 50;

create or replace function myfunction(p number)
return number as
begin
  dbms_output.put_line('In function for p=' || p);
  return mod(p,3);
end;
/

set serveroutput on

select myfunction(b)
from mytable
where a = 1;

MYFUNCTION(B)
-------------
            1
            2
            0
            1
            2

In function for p=1
In function for p=11
In function for p=21
In function for p=31
In function for p=41

Функция вызывается только для строк, которые соответствуют фильтру предложений where.Однако, насколько я знаю, это не гарантировано.

Во втором примере все гораздо сложнее и в значительной степени зависит от оптимизатора.Для моей простой демонстрации оптимизатор (в данном случае 11gR2) сначала оценивает a и вызывает функцию только для тех строк, которые соответствуют этому;но затем он вызывает его снова для значения списка выбора:

select myfunction(b)
from mytable
where a = 1
and myfunction(b) = 2;

MYFUNCTION(B)
-------------
            2
            2

In function for p=1
In function for p=11
In function for p=11
In function for p=21
In function for p=31
In function for p=41
In function for p=41

Функция вызывается для каждой из пяти строк, где a=1, как и раньше, и для тех, где myfunction(b) = 2 она называетсяво второй раз, чтобы получить значение в наборе результатов.

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

select myfunction(b)
from mytable
where myfunction(b) = 2
and a = 1;

select x
from (
  select myfunction(b) as x
  from mytable
  where a = 1
)
where x = 2;

select x
from (
  select /*+ materialize */ myfunction(b) as x
  from mytable
  where a = 1
)
where x = 2;

with t (x) as (
  select myfunction(b)
  from mytable
  where a = 1
)
select x
from t
where x = 2;

Оптимизатор внутренне переписывает их все в один и тот же запрос, и вы все равно получаете все семь вызовов функций.Добавление недокументированной подсказки меняет его:

with t (x) as (
  select /*+ materialize */ myfunction(b)
  from mytable
  where a = 1
)
select x
from t
where x = 2;

         X
----------
         2
         2

In function for p=1
In function for p=11
In function for p=21
In function for p=31
In function for p=41

, но вы не можете (или не должны) действительно использовать или полагаться на это.

Индексация, разбиение, версия оптимизатора,статистика и т. д. будут влиять на поведение оптимизатора для вашего запроса.

И, как следует учитывать, у вас может быть индекс на основе функции или детерминированная функция ...

Итак ... это зависит.

0 голосов
/ 26 сентября 2018

SQL не имеет порядка выполнения.Это декларативный язык.В конечном счете, единственный правильный «порядок» - это тот, который описан в фактическом плане выполнения.См. Отображение планов выполнения с использованием классов событий SQL Server Profiler и Отображение графических планов выполнения (SQL Server Management Studio).

Совсем другое дело - как проецируются запросы, подзапросы и выраженияв «действительность».Например, если у вас есть псевдоним в списке проекции SELECT, можете ли вы использовать псевдоним в предложении WHERE?Например:

SELECT col1+col2 as col3

ОТ ГДЕ col3 = ...;

Знание порядка, в котором выполняется SQL-запрос, может значительно помочь нам в оптимизации наших запросов.Это особенно верно для больших и сложных запросов, где знание порядка выполнения может спасти нас от нежелательных результатов и помочь нам создавать запросы, которые выполняются быстрее.

СМОТРЕТЬ Выполнение Где, ON, Группировать по

Пожалуйста, избегайте использования функции в условии where, она будет проверяться для каждой записи в таблице.

0 голосов
/ 26 сентября 2018

Порядок выполнения на самом деле ничего не значит для SQL в целом, особенно для сложной базы данных, такой как Oracle.На самом деле запускается ориентированный ациклический граф, представляющий такие операторы, как «вложенные циклы» и «сканирование диапазона индекса».Это операторы, которые вы не видите непосредственно в операторе SQL.

Итак, вы должны быть готовы к тому, что эта функция будет вызываться 100 раз или 1 000 000 раз.И при других обстоятельствах Oracle может выбрать любой из них.

Что касается предложения where, то лучше не повторять вызов функции.В Oracle 12C я бы использовал боковое соединение.В более ранних версиях CTE или подзапрос должен сообщать, что функция не вызывается дополнительное время для where.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...