Оптимизировать escape JSON в PostgreSQL 9.0 - PullRequest
5 голосов
/ 14 февраля 2011

В настоящее время я использую эту функцию JSON Escape в PostgreSQL в качестве замены для будущей собственной поддержки 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;

Ответы [ 3 ]

7 голосов
/ 27 марта 2011

Исповедь: я студент Google Summer of Code 2010, который собирался попытаться обеспечить поддержку JSON в PostgreSQL 9.1.Хотя мой код был довольно полнофункциональным, он не был полностью готов для апстрима, и сообщество разработчиков PostgreSQL рассматривало некоторые альтернативные реализации.Однако, с приближением весенних каникул, я надеюсь закончить свою переписку и завершить ее на этой неделе.

В то же время, вы можете загрузить и установить work-текущий тип данных 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

Хотя сборку и установку необходимо выполнить только один раз, json.sql необходимо выполнитьЗапустите для каждой базы данных, на которой вы планируете использовать тип данных JSON.

После установки вы можете выполнить:

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

Обратите внимание, что это не исключает символы не-ASCII.

6 голосов
/ 15 февраля 2011

Все мои подходы сводятся к тому, чтобы «сделать это по-другому»:

  • Напишите это на другом языке, например используйте pl / perl, pl / python, pl / ruby ​​
  • Написать обертку вокруг некоторой внешней библиотеки JSON, написанной на C
  • Выполнять экранирование 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]);
  $$;

Быстрый тест показывает, что это примерно в 15 раз быстрее, чем функция plpgsql (хотя она возвращает кавычки вокруг значения, которое вы, вероятно, хотите удалить)

1 голос
/ 27 декабря 2011

Я нашел функцию PostgreSQL, реализованную в C здесь: http://code.google.com/p/pg-to-json-serializer/

Я не сравнивал его с вашим методом PLSQL, но он должен быть быстрее любого интерпретируемого языка.

Еще один: http://miketeo.net/wp/index.php/projects/json-functions-for-postgresql

...