在PostgreSQL 9.0中优化转义JSON

gra*_*bot 5 postgresql json query-optimization

我目前在PostgreSQL中使用这个JSON转义函数作为未来原生JSON支持的代表.虽然它有效,但它也限制了我们的系统性能.我该如何进行优化呢?也许某种查找数组?

CREATE OR REPLACE FUNCTION escape_json(i_text TEXT) 
RETURNS TEXT AS
$body$                                                  
DECLARE
  idx INTEGER;
  text_len INTEGER;   
  cur_char_unicode INTEGER;
  rtn_value TEXT := i_text;
BEGIN
  -- $Rev: $ --
  text_len = LENGTH(rtn_value);
  idx = 1; 

  WHILE (idx <= text_len) LOOP
    cur_char_unicode = ASCII(SUBSTR(rtn_value, idx, 1));

    IF cur_char_unicode > 255 THEN
      rtn_value = OVERLAY(rtn_value PLACING (E'\\u' || LPAD(UPPER(TO_HEX(cur_char_unicode)),4,'0')) FROM idx FOR 1);
      idx = idx + 5;
      text_len = text_len + 5;
    ELSE
      /* is the current character one of the following: " \ / bs ff nl cr tab */
      IF cur_char_unicode IN (34, 92, 47, 8, 12, 10, 13, 9) THEN
        rtn_value = OVERLAY(rtn_value PLACING (E'\\' || (CASE cur_char_unicode
                                                         WHEN 34 THEN '"'
                                                         WHEN 92 THEN E'\\'
                                                         WHEN 47 THEN '/'
                                                         WHEN  8 THEN 'b'
                                                         WHEN 12 THEN 'f'
                                                         WHEN 10 THEN 'n'
                                                         WHEN 13 THEN 'r'
                                                         WHEN  9 THEN 't'
                                                          END)
                                        )
                                FROM idx FOR 1);

        idx = idx + 1;
        text_len = text_len + 1;
      END IF;
    END IF;

    idx = idx + 1;
  END LOOP;                   

  RETURN rtn_value;
END;
$body$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

Joe*_*ams 7

忏悔:我是Google Summer of Code 2010学生,他试图将JSON支持带到PostgreSQL 9.1.虽然我的代码功能相当完整,但它还没有为上游做好准备,而PostgreSQL开发社区正在研究一些替代实现.然而,随着春假即将到来,我希望能够完成我的重写,并在本周给予最后的推动.

同时,您可以下载并安装正在进行中的JSON数据类型模块,该模块应该适用于PostgreSQL 8.4.0及更高版本.它是一个PGXS模块,因此您可以编译和安装它,而无需编译所有PostgreSQL.但是,您将需要PostgreSQL服务器开发标头.

安装如下:

git clone git://git.postgresql.org/git/json-datatype.git
cd json-datatype/
USE_PGXS=1 make
sudo USE_PGXS=1 make install
psql -f json.sql <DBNAME1> # requires database superuser privileges
Run Code Online (Sandbox Code Playgroud)

虽然构建和安装只需要完成一次,但是json.sql需要在计划使用JSON数据类型的每个数据库上运行.

安装完成后,您现在可以运行:

=> SELECT to_json(E'"quotes and \n newlines"\n'::TEXT);
            to_json             
--------------------------------
 "\"quotes and \n newlines\"\n"
(1 row)
Run Code Online (Sandbox Code Playgroud)

请注意,这不会转义非ASCII字符.


ara*_*nid 6

我所有的方法归结为"以其他方式做":

  • 用其他语言写,例如使用pl/perl,pl/python,pl/ruby
  • 编写一个用C编写的外部JSON库的包装器
  • JSON是否在客户端而不是在查询中进行转义(假设您的客户端具有一些良好的JSON转义支持)

根据我的经验,pl/pgsql在这种情况下并不快 - 它的优势在于它与数据库交换数据的整体支持,而不是作为通用编程语言.

例:

create or replace function escape_json_perl(text) returns text 
  strict immutable
  language plperlu as $$
    use JSON;
    return JSON->new->allow_nonref->encode($_[0]);
  $$;
Run Code Online (Sandbox Code Playgroud)

快速测试表明这比plpgsql函数快15倍(虽然它返回你可能想要剥离的值的引号)