2

我正在寻找在表中解析、验证和插入数据的最快方法( Postgresql 9.3)

数据是一个包含 1..N 个项目的 json 数组。

[{"name":"a","value":"1"},{"name":"b","value":"2"}]

该表如下所示:

CREATE TABLE logs
(
  id serial NOT NULL,
  name text ,
  value text,
  CONSTRAINT "log_Pkey" PRIMARY KEY (id)
);

为此,我有存储过程:

CREATE OR REPLACE FUNCTION insert_logs(v json)
  RETURNS  integer AS
$BODY$
DECLARE
    sql text;
    i json;
    logs_part_id int;
BEGIN
    SELECT INTO logs_part_id id from another_table_with_that_id where some_condition.

    sql = '';
     FOR i IN SELECT * FROM json_array_elements(v)
      LOOP
      sql = sql||'insert into logs_'||logs_part_id ||'
        (name, value)
         values( ' ||quote_literal(i->>'name')||' , ' ||quote_literal(i->>'value')||' );';

      END LOOP;
    raise notice '%',sql;

    EXECUTE sql;
    return 1;

END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

(函数返回整数作为响应状态)

函数调用:

select * from insert_logs('[{"name":"a","value":"1"},{"name":"b","value":"2"}]'::json);

实际上,“insert..”语句要大得多——要插入 15 列,显然应该检查其中的一些列,以防止 sql 注入。

问题:有没有办法重写这个存储过程以提高性能?我应该使用准备好的语句吗?

编辑。

我构建 sql 字符串的原因是因为表分区导致表名未知。表名格式为:logs_id where id - int 是在插入之前获得的。

4

2 回答 2

3

如果您需要加快查询速度,json_populate_recordset()正是您所需要的:

insert into logs
select * from json_populate_recordset(null::logs, '[...]')

对于 SQL 注入:您应该始终使用准备好的语句,或者至少使用单独发送的参数执行您的 sql(PQexecParams()如果您直接使用 libpq,则使用 f.ex.)。

于 2014-09-22T08:31:37.840 回答
2

你为什么要构建一个 SQL 多语句字符串,然后再EXECUTEing 它?

只是:

  insert into logs (name, value)
  values( i->>name , i->>value );

不需要显式引用,因为i->>name它是text作为绑定参数插入到insertPL/PgSQL 中的值。它永远不会被解析为 SQL。

如果您必须动态构建语句(例如,根据评论改变表名),请使用EXECUTE ... USINGwith format

  EXECUTE format('insert into %I (name, value) values( $1, $2 );', 'logs_'||log_partition_id) 
     USING i->>name , i->>value;

在你的情况下

于 2014-09-22T08:36:10.777 回答