Как создать индекс для столбца XML в PostgreSQL с помощью выражения xpath? - PullRequest
0 голосов
/ 04 сентября 2018

Я сталкиваюсь с этой ошибкой при попытке создать индекс btree для столбца с типом данных XML, который использует выражение xpath в AuroraDB - PostgreSQL 9.6:

ERROR:  could not identify a comparison function for type xml
SQL state: 42883

Этот поток 2009 без четкого разрешения - единственный, который я нашел, обсуждая это сообщение об ошибке в отношении создания индекса на основе xpath для намного более ранней версии PostgreSQL: https://www.postgresql -archive.org / Замедленное выберите раза-на-выбор-с-XPATH-td2074839.html

В моем случае мне также нужно указать пространства имен, и оригинальный постер в этом потоке приведёт результат выражения xpath к тексту [], что для меня тоже становится ошибкой - но зачем это вообще нужно? Я также не вижу, чтобы PostgreSQL использовал мой индекс, даже когда мне нужно пройти через тысячи строк.

Итак, я опробовал более простой случай, и ошибка по-прежнему возникает - пожалуйста, проясните, почему, если вы могли бы:

CREATE TABLE test
(
    id integer NOT NULL,
    xml_data xml NOT NULL,
    CONSTRAINT test_pkey PRIMARY KEY (id)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;



CREATE INDEX test_idx
    ON test USING btree 
    (xpath('/book/title', xml_data))

и полученное сообщение:

ERROR:  could not identify a comparison function for type xml
SQL state: 42883

Кодировка базы данных - UTF8. Тип сортировки и символов en_US.UTF-8.

Некоторые примеры операторов вставки тоже:

insert into source_data.test(id, xml_data) 
values(1, XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>1</chapter><chapter>2</chapter></book>'))

insert into source_data.test(id, xml_data) 
values(2, XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Apropos</title><chapter>1</chapter><chapter>2</chapter></book>'))

1 Ответ

0 голосов
/ 09 сентября 2018

Вы получаете эту ошибку, потому что XML-тип данных не предоставляет операторов сравнения , следовательно, вы не можете создать индекс для результата xpath(), потому что он возвращает массив значений XML .

Поэтому при создании индекса вам нужно привести выражение XPath к текстовому массиву:

CREATE INDEX test_idx
ON test USING BTREE 
    (cast(xpath('/book/title', xml_data) as text[])) ;

Этот индекс затем используется при запросе таблицы:

EXPLAIN ANALYZE
SELECT * FROM test where
cast(xpath('/book/title', xml_data) as text[]) = '{<title>Apropos</title>}';

дает

                                                    QUERY PLAN                                                     
-------------------------------------------------------------------------------------------------------------------
Index Scan using test_idx on test  (cost=0.13..8.15 rows=1 width=36) (actual time=0.034..0.038 rows=1 loops=1)
    Index Cond: ((xpath('/book/title'::text, xml_data, '{}'::text[]))::text[] = '{<title>Apropos</title>}'::text[])
Planning time: 0.168 ms
Execution time: 0.073 ms (4 rows)

То же самое работает при использовании text():

CREATE INDEX test_idx
ON test USING BTREE 
    (cast(xpath('/book/title/text()', xml_data) as text[])) ;

explain analyze select * from test where
cast(xpath('/book/title/text()', xml_data) as text[]) = '{Apropos}';

дает

                                                   QUERY PLAN                                                   
----------------------------------------------------------------------------------------------------------------
 Index Scan using test_idx on test  (cost=0.13..8.15 rows=1 width=36) (actual time=0.034..0.038 rows=1 loops=1)
   Index Cond: ((xpath('/book/title/text()'::text, xml_data, '{}'::text[]))::text[] = '{Apropos}'::text[])
 Planning time: 0.166 ms
 Execution time: 0.076 ms
(4 rows)

Обратите внимание, что я принудительно использовал индекс с помощью следующей команды, поскольку в созданной мной тестовой таблице было только 4 строки.

SET enable_seqscan TO off;
...