2014-01-21 26 views
0

我有一個非常昂貴的PLSQL函數,做了很多遞歸運算處理的查詢:如何創建Postgres的臨時緩存/桌,持續查詢的時間

SELECT a, b, expensive_recursion(c, d, e) FROM my_table 

功能expensive_recursion()有PLPGSQL這樣的:

CREATE OR REPLACE FUNCTION expensive_recursion(col varchar, parent varchar, date varchar) 
RETURNS integer AS 
$BODY$ 
DECLARE 
    _value integer; 
    _rec record; 
BEGIN 

    -- get the value for the current parent that matches the range 
    EXECUTE 'SELECT value_'||col||' FROM foo WHERE foo.id = '||quote_literal(parent)||' AND foo.range = '||quote_literal(range) INTO _value; 


    -- get all children of parent and sum their values 
    FOR rec IN EXECUTE 'SELECT child FROM relationships WHERE parent = '||quote_literal(parent) LOOP 
    _value = _value + expensive_recursion(col, rec.child, range); 
    END LOOP; 
    RETURN _value; 

END; 
$BODY$ 
LANGUAGE plpgsql STABLE COST 1000; 

雖然這工作,我想啓用緩存,不僅對當前行多數民衆贊成在遞歸,但對當前查詢中的所有行,並有一次查詢已完全執行緩存清除。

例如,對於一些僞代碼的原始功能: CREATE OR REPLACE FUNCTION expensive_recursion(COL VARCHAR,父VARCHAR,範圍VARCHAR) RETURNS整數AS $ BODY $ DECLARE _value整數; _rec記錄; BEGIN

-- pseudo-code to check the cache and get the cached value or insert into cache 
    IF parent AND range IN cache 
    RETURN SELECT value FROM cache WHERE cache.parent = parent and cache.range = range; 
    END IF; 

    -- get the value for the current parent that matches the range 
    EXECUTE 'SELECT value_'||col||' FROM foo WHERE foo.id = '||quote_literal(parent)||' AND foo.range = '||quote_literal(range) INTO _value; 


    -- get all children of parent and sum their values 
    FOR rec IN EXECUTE 'SELECT child FROM relationships WHERE parent = '||quote_literal(parent) LOOP 
    _value = _value + expensive_recursion(col, rec.child, range); 
    END LOOP; 

    -- put new value in cache 
    INSERT INTO cache (value, parent, range) VALUES (_value, parent, range); 

    -- final value with sum for parent and its children 
    RETURN _value; 
END; 
$BODY$ 
LANGUAGE plpgsql STABLE COST 1000; 

有沒有辦法做到這一點,必須創建緩存/刪除?我可以使用臨時表或者我在plpgsql函數中管理的一些結構/類型。訣竅是多個用戶可以執行此功能,並且出於應用程序特定的原因,緩存不能跨查詢共享。

回答

1

您可以像普通表一樣創建臨時表;只是限定它相應:

create temporary table (…); 

http://www.postgresql.org/docs/current/static/sql-createtable.html

有微小的缺點,並在此過程中一個潛在的重大上攻。缺點是,如果臨時設置很小,則會創建並隨後刪除目錄中的行,並在流程中添加需要清理的死行。好處在於,如果臨時設置很大,您可以先創建一個索引並最終在該表上執行查詢操作,然後執行analyze

您可以在其定義中使用on commit來控制臨時表在事務結束時還是在會話結束時被刪除。

添加到這一點,雖然,另一種方法做遞歸查詢是使用熱膨脹係數,也稱爲與查詢:

http://www.postgresql.org/docs/current/static/queries-with.html

對於所有意圖和目的,它創建一個匿名(非索引)臨時表。你可以遞歸地做到這一點,並且這樣做可以非常有效。

方法嘗試更改查詢和底層邏輯,以便首先嚐試使用CTE。如果一切都失敗了,那麼實際使用臨時表。