Ну, по крайней мере, индекс используется.Вы получаете сканирование индекса растрового изображения вместо обычного сканирования индекса, что означает, что функция xpath () будет вызываться много раз.
Давайте сделаем небольшую проверку:
CREATE TABLE foo ( id serial primary key, x xml, h hstore );
insert into foo (x,h) select XMLPARSE( CONTENT '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<object_id>2</object_id>
<pack_form_id>' || n || '</pack_form_id>
<prod_form_id>34</prod_form_id>
</row>' ),
('object_id=>2,prod_form_id=>34,pack_form_id=>'||n)::hstore
FROM generate_series( 1,100000 ) n;
test=> EXPLAIN ANALYZE SELECT count(*) FROM foo;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Aggregate (cost=4821.00..4821.01 rows=1 width=0) (actual time=24.694..24.694 rows=1 loops=1)
-> Seq Scan on foo (cost=0.00..4571.00 rows=100000 width=0) (actual time=0.006..13.996 rows=100000 loops=1)
Total runtime: 24.730 ms
test=> explain analyze select * from foo where (h->'pack_form_id')='123';
QUERY PLAN
----------------------------------------------------------------------------------------------------
Seq Scan on foo (cost=0.00..5571.00 rows=500 width=68) (actual time=0.075..48.763 rows=1 loops=1)
Filter: ((h -> 'pack_form_id'::text) = '123'::text)
Total runtime: 36.808 ms
test=> explain analyze select * from foo where ((xpath('//pack_form_id/text()'::text, x))[1]::text) = '123';
QUERY PLAN
------------------------------------------------------------------------------------------------------
Seq Scan on foo (cost=0.00..5071.00 rows=500 width=68) (actual time=4.271..3368.838 rows=1 loops=1)
Filter: (((xpath('//pack_form_id/text()'::text, x, '{}'::text[]))[1])::text = '123'::text)
Total runtime: 3368.865 ms
Как мы видим,
- сканирование всей таблицы с количеством (*) занимает 25 мс
- извлечение одного ключа / значения из хранилища добавляет небольшую дополнительную стоимость, около 0,12 мкс / строка
- извлечение одного ключа / значения из xml с использованием xpath добавляет огромные затраты, около 33 мкс / строка
Выводы:
- xml работает медленно (но все это знают)
- , если вы хотите поместить гибкое хранилище ключей / значений в столбец, используйте hstore
Кроме того, поскольку ваши xml-данные довольно большие, они будут поджарены (сжаты и сохранены вне основной таблицы).Это делает строки в основной таблице намного меньше, а значит, на каждой странице больше строк, что снижает эффективность растровых сканирований, поскольку все строки на странице должны быть перепроверены.
Вы можете исправить это.По какой-то причине функция xpath () (которая очень медленная, поскольку она обрабатывает xml) имеет такую же стоимость (1 единицу), как, скажем, целочисленный оператор "+" ...
update pg_proc set procost=1000 where proname='xpath';
Вы можетенужно настроить стоимость стоимости.Получив правильную информацию, планировщик знает, что xpath медленный, и будет избегать сканирования индекса растрового изображения, используя вместо этого сканирование индекса, которое не требует повторной проверки условия для всех строк на странице.
Обратите внимание, что этоне решает проблему оценки строк.Поскольку вы не можете АНАЛИЗИРОВАТЬ внутреннюю часть xml (или hstore), вы получаете оценки по умолчанию для числа строк (здесь 500).Таким образом, планировщик может быть совершенно не прав и выбрать катастрофический план, если в него вовлечены некоторые объединения.Единственное решение - использовать правильные столбцы.