2016-03-10 3 views
0

Я (должен) использовать базу данных Postgres 8.4. В этой базе данных я создать функцию:Функция Postgres медленнее, чем запрос/Postgres 8.4

CREATE OR REPLACE FUNCTION counter (mindate timestamptz,maxdate timestamptz) RETURNS integer AS $func$ 
DECLARE result integer; 
BEGIN 
Select INTO result COUNT(*) AS counter from columname where starttime BETWEEN $1 and $2; 
Return result; 
END 
$func$ LANGUAGE plpgsql; 

запрос:

apptelemetry=# select counter('2016-03-01 00:00:00','2016-03-11 00:00:00'); 
requestcounter 
---------------- 
      8893 
(1 row) 

Time: 4.740 ms 

Когда я сделать нормальный запрос:

apptelemetry=# select Count(*) from columname where starttime BETWEEN '2016-03-01 00:00:00' AND '2016-03-11 00:00:00'; 
count 
------- 
    8893 
(1 row) 

Time: 3.214 ms 

Почему функция медленнее, чем обычный запрос? Есть ли у меня рекомендации по производительности?

Regrads

+0

это произойдет, если запустить тот же запрос несколько раз? и у вас есть индекс для 'starttime', потому что это не должно быть так медленно, независимо от порядка. –

+2

Для этого вам не нужен 'PL/pgSQL'. Накладные расходы на 1 мс вполне могут быть вызваны накладными расходами на вызов PL/pgSQL. Что произойдет, если вы измените это на простую функцию 'language sql'? –

+0

«Почему функция медленнее обычного запроса?» --- Почему функция должна быть быстрее? Просто потому, что вы что-то вложили в функцию, это не ускоряет работу автоматически. – zerkms

ответ

2

Запросы в PLpgSQL оптимизированы вслепую. Иногда план выполнения может быть субоптимальным для некоторых параметров.

PLpgSQL повторяет план выполнения любого запроса. Он имеет некоторые преимущества (нет повторного дорогостоящего планирования запросов), но он также имеет некоторые недостатки (план не оптимизирован для реальных значений, он оптимизирован для наиболее вероятных значений). Современные версии Postgres немного умнее.

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

CREATE OR REPLACE FUNCTION counter (mindate timestamptz,maxdate timestamptz) RETURNS integer AS $func$ 
DECLARE result integer; 
BEGIN 
    EXECUTE 'SELECT COUNT(*) FROM columname 
      WHERE starttime BETWEEN $1 and $2' 
    INTO result USING mindate, maxdate; 
    RETURN result; 
END 
$func$ LANGUAGE plpgsql; 

Одна статья об этой проблеме: http://blog.endpoint.com/2008/12/why-is-my-function-slow.html

+0

Большое спасибо! :-) Работает намного лучше, чем у меня! – liquid

1

функция А PL/PgSQL имеет накладные расходы для создания своей среды. В вашем случае, однако, вы можете использовать функцию языка SQL, который является гораздо более эффективным:

CREATE FUNCTION counter (mindate timestamptz, maxdate timestamptz) RETURNS integer AS 
$func$ 
    SELECT count(*) FROM columname WHERE starttime BETWEEN $1 AND $2; 
$func$ LANGUAGE sql; 

Только когда нужна функциональность, которая не поддерживается на языке SQL, как условное ветвление, вы должны использовать PL/PgSQL ,

При этом фактическое время выполнения может зависеть от многих факторов внутри или вне СУБД, поэтому на такое воздействие может влиять простое сравнение одного прогона.

+0

В этом случае plpgsql не имеет накладных расходов, –

+0

Thx! Работа штрафа :-) – liquid

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