POSTGRES函数执行几次后需要很长时间

时间:2015-10-21 16:37:48

标签: java postgresql

我使用java在postgres中调用一个简单的upsert函数。

DROP FUNCTION IF EXISTS UPSERT
CREATE FUNCTION UPSERT(integer,real,real,real,int,real,int,int,int,int,int,real,int,character varying,character varying,int,character varying, timestamp without time zone,real,int,int,int,int,boolean) RETURNS text AS $$

DECLARE
       reccount integer := 0;
       BEGIN


SELECT COUNT(*) INTO reccount FROM mytbl  WHERE id =  $1;    

IF reccount = 0 THEN 

    EXECUTE  ' INSERT INTO mytbl  
 VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, ST_SetSRID(ST_MakePoint($3, $2), 4326), $18 )'
 USING  $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22 , $23;              

ELSE 

 EXECUTE  'UPDATE mytbl  SET ..... WHERE id =  $1' USING $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19,
$20, $21, $22 , $23;    

END IF ;

RETURN 'V' || reccount ;    

END;
    $$ LANGUAGE plpgsql;

我正在尝试写2500条记录。写完250条记录之后,它正在减慢这个过程。在写了几条记录之后,同样的操作花了很长时间。最初花了几毫秒写了250+记录它慢慢增加到30或40秒。但是,如果我删除索引并且只是插入或更新而不执行选择,则首先一切正常。这是一段时间后变慢的select语句。我正在使用java for循环再次调用上面的函数。

可能会发生什么?

以下是java代码。

 CallableStatement upperProc = _conn.prepareCall("{ call UPSERT( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? ) }");
           //upperProc.registerOutParameter(1, Types.VARCHAR);

           upperProc.setInt(1, message.getsi());
           upperProc.setFloat(2, ..);
           ....
                   ....
           ....
                   upperProc.setInt(23, ...);
           upperProc.setBoolean(24,inCache );

1 个答案:

答案 0 :(得分:1)

COUNT期望使用多行,并且很可能花费更多时间表中的记录越多。

首选使用EXISTS查询,该查询始终只查找与条件匹配的单行。

因此我们可以处理reccount变量,并编写如下条件:

IF EXISTS (SELECT 1 FROM mytbl WHERE id = $1 ) THEN

    EXECUTE 'UPDATE mytbl ...';

ELSE

    EXECUTE 'INSERT INTO mytbl ...';

END IF;

备注

  • 如果插入和更新语句不是动态构建的(它们总是具有相同的结构,只是值不同),那么直接使用INSERT INTOUPDATE会更有效率而不是用于动态构建查询的EXECUTE

  • 另一种选择是尝试更新记录,如果没有更新记录,则执行插入操作。在这种情况下,请保留变量reccount

    EXECUTE 'UPDATE mytbl ...';
    
    GET DIAGNOSTICS reccount = ROW_COUNT;
    
    IF reccount = 0 THEN
    
         EXECUTE 'INSERT INTO mytbl ...';
    
    END IF;
    

    如果您第一次提出不使用EXECUTE的建议,那么您可以改为使用FOUND变量:

    UPDATE mytbl SET field1 = $1, field2 = $2, ....;
    
    IF NOT FOUND THEN
    
         INSERT INTO mytbl (field1, field2, ....) VALUES ($1, $2, ...);
    
    END IF;
    
    section 40.5.5 of the PostgreSQL documentation中记录了

    GET DIAGNOSTICSFOUND