Как создать индекс для столбца XML в PostgreSQL с выражением xpath?
я сталкиваюсь с этой ошибкой при попытке создать индекс 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/Slow-select-times-on-select-with-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 ответов
вы получаете эту ошибку, потому что тип данных 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;