我使用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 );
答案 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 INTO
和UPDATE
会更有效率而不是用于动态构建查询的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 DIAGNOSTICS
和FOUND
。