2017-03-29 4 views
0

정렬 메커니즘으로 작동하는 임시 테이블/임시 정렬에서 다음 테이블로 계단식 정렬하는 임시 테이블이 7 개있는 함수를 최적화하려고합니다. 마지막 하나, 예를 들어 일곱 번째 임시 테이블/정렬.plpgpsql - 정렬을 수행하기 위해 임시 테이블의 다른 형식

Gist here : 이러한 종류의 코드는 반드시 금지되어야합니다.

WITH 정렬을 실제 임시 테이블 (예 : CREATE TEMPORARY TABLE <table_name> AS SELECT col1 FROM another_table;)으로 바꾸려고합니다. 목표는 현재 형식의 쿼리가 매우 느리기 때문에 성능을 향상시키는 것입니다.

내가
CREATE OR REPLACE FUNCTION report.get_sa001(
    IN "date_D" timestamp without time zone, 
    IN "date_F" timestamp without time zone, 
    IN frequence integer) 
RETURNS TABLE(
    "Period_date" timestamp without time zone, 
    "Site" character varying, 
    "Customer_code" character varying, 
    "Internal_reference" character varying, 
    "InvoiceNumber" character varying, 
    "Value_in_currency" numeric, 
    "Value_in_EUR" numeric, 
    "Value_Budget_in_EUR" numeric, 
    "Selling_price_CUR" numeric, 
    "Selling_price_EUR" numeric, 
    "Currency_code" character varying, 
    "Selling_quantity" numeric, 
    "Variance_price_CUR" numeric, 
    "Variance_price_EUR" numeric, 
    "Variance_value_CUR" numeric, 
    "Variance_value_EUR" numeric, 
    "Selling_date" timestamp without time zone) AS 

$BODY$ 
DECLARE 
    p_debut timestamp without time zone; 
DECLARE 
    p_fin timestamp without time zone; 
BEGIN 
    p_debut = dw.get_period_end("date_D", "frequence"); 
    p_fin = dw.get_period_end("date_F", "frequence"); 

    RETURN QUERY 
    CREATE TEMPORARY TABLE "dates_1" AS 
     SELECT 
     p_debut::date + n AS "date", 
     dw.period_frequency(p_debut::date + n) AS "frequency"    
     FROM generate_series(0, p_fin::date - p_debut::date) AS x(n) 
     WHERE (dw.period_frequency(p_debut::date + n) & frequence != 0); 

    SELECT * FROM "dates_1"; -- Thanks to Vao Tsun 
END; 
$BODY$ 
    LANGUAGE plpgsql STABLE 
    COST 100 
    ROWS 1000; 

을 제시 한 변화

함수의 생성은 잘하지만 기능이 방법

SELECT * FROM report.get_sa001('2017-01-01'::date, '2017-01-31'::date, 32) 

을 실행할 때 내가 가진 무엇

ERROR: cannot open query CREATE TABLE AS like cursor 
État SQL :42P11 
Contexte : fonction PL/pgsql report.get_sa001(timestamp without time zone,timestamp without time zone,integer), ligne 11 à RETURN QUERY 

CREATE TEMPORARY TABLESELECT * INTO TEMPORARY TABLE으로 대체하려고 시도했습니다. 생성은 다시 ok이지만 실행 중에도 동일한 오류가 발생합니다.

SO의 보관 파일을 확인하면 PLPGSQL에서 임시 테이블 (here 확인)을 사용하는 것을 금지합니다.

아이디어가 있다면 그 이상을 환영합니다.

감사

+0

함수가 테이블을 반환하도록 정의되었지만 쿼리'create temporary table ... '을 반환합니다. 작동하지 않습니다. create table의 결과가 반환 된 열이 아닙니다. 당신은 'SELECT * FROM "Sales_final"; "과 같은 smth를 추가해야합니다. –

+0

안녕하세요 @ VaoTsun, 답장을 보내 주셔서 감사합니다. 내가 언급 한 부분을 추가했지만 그럴 것 같지 않습니다. 두려워요. –

+0

@VaoTsun 실제로 동일한 오류입니다 –

답변

1

이 기능에 임시 테이블을 생성하여 아무 문제 없습니다 :

t=# create or replace function so37() returns table (i int) as 
$$ 
declare 
begin 
create temporary table a as select 2; 
return query select * from a; 
end; 
$$ language plpgsql 
; 
CREATE FUNCTION 
t=# select * from so37(); 
i 
--- 
2 
(1 row) 

는하지만, 그들은 당신이 존재하는 경우 드롭 테이블이 부족하거나 대신 현재의 예에서 예를 들어, 유지되어야한다

t=# select * from so37(); 
ERROR: relation "a" already exists 
CONTEXT: SQL statement "create temporary table a as select 2" 
PL/pgSQL function so37() line 4 at SQL statement 

을 그리고 CTE는 더 나은 altern이라고 생각 :의 당신이하지 않으면, 두 번째 실행이 실패하기 때문에, 당신은에 삽입해야 테이블을 생성 함수에서 임시 테이블을 만드는 데있어 ...

+0

cte는 좋은 대안이 아니다. 10000 lines = 15mn –

+0

임시 테이블 생성 중에'on commit drop '을 사용할 수 있습니다. 그래서 postgres는 세션의 default-end 대신 transaction의 끝에서 drop합니다. –

+0

은 모든 함수를 실행하기 전에 커밋해야 함을 사용합니다. –