2014-10-21 3 views
0

Я хотел бы написать функцию API, которая является модульной. Проблема в том, что в модульных деталях есть одинаковых запросов. У меня есть подозрение, что одни и те же запросы в каждой подфункции будут влиять на производительность.Функция Break PL/pgSQL на более мелкие части

Пример:

MAIN_FUNCTION: base_data(customer_id, user_id) { 
     SELECT * 
     FROM get_absence(customer_id, user_id) 
     JOIN get_work_hours(customer_id, user_id) 
     USING (worker_id) 
    } 

    get_absence(customer_id, user_id) { 
     RETURN QUERY 
     SELECT * 
     FROM get_user_workers(customer_id, user_id) 
     JOIN absence_table 
     USING (worker_id) 
    } 

    get_work_hours(customer_id, user_id) { 
     RETURN QUERY 
     SELECT * 
     FROM get_user_workers(customer_id, user_id) 
     JOIN workhours_table 
     USING (worker_id) 
    } 

К сожалению для псевдокода, но это немного короче. В основном, большинство подфункций будет содержать запрос get_user_workers. Если бы я построил большую и скучную функцию, я бы запросил рабочих с общим табличным выражением.

Как добиться читаемости и модульности вместо бесчисленных строк запросов?

+2

*** Всегда *** включать полную функцию заголовок (и нижние колонтитулы) с именем, параметрами, типами данных, типа возвращаемого значения языка декларация, ... И, конечно, ваша версия Postgres. –

+0

Является ли ваше последнее предложение действительно вашим вопросом? Остальная часть вашего сообщения звучит так, как будто вы действительно спрашиваете: «Как мне избежать вызова get_user_workers() несколько раз»? –

+0

Этот стиль является самым худшим с точки зрения производительности. Вы можете очень эффективно блокировать оптимизатор запросов. SQL не поддерживает эту небольшую детализацию. Если вам это нужно, используйте вместо них тривиальные однострочные функции запроса sql. –

ответ

2

Вы можете сделать это легко:

CREATE FUNCTION get_absence(...) RETURNS TABLE (...) ...; 
CREATE FUNCTION get_work_hours(...) RETURNS TABLE (...) ...; 

CREATE FUNCTION base_data(_customer_id int, _user_id int) 
    RETURNS TABLE (...) AS 
$func$ 
    SELECT a.*, w.* 
    FROM get_absence(_customer_id, _user_id) a 
    JOIN get_work_hours(_customer_id, _user_id) w ON w.??? = a.???; 
$func$ LANGUAGE sql; 

Использование функции SQL для простого примера. То же самое относится к PL/pgSQL, потому что проблема - вопрос SQL.

В предложении FROM можно использовать функцию возврата номера , как и таблицу. Но вызова функции с возвращающим набором:

SELECT * FROM base_data(1,2);

Имейте в виде, что простые функции SQL могут быть «встраиваются», в то время как функции PL/PgSQL всегда выполняется отдельно (ставят в качестве оптимизации барьера) - но их план выполнения сохранены и повторно использованы в одном сеансе (если Postgres считает, что это будет дешевле). У каждого есть свои плюсы и минусы.

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

Деталь:

+1

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

+0

Хорошо, функция thingy кажется не очень чистой. base_data должен содержать все функции, которые будут использоваться, я не могу скрыть некоторые функции на более низких уровнях. Спасибо, Павел, я попытаюсь использовать тао зрения. – user1190411

+0

Единственное, что меня мучает с представлениями, это то, что я не могу использовать в них generate_series. Это означает, что большие куски SQL внутри основной функции окружены party by views. – user1190411

Смежные вопросы