No, alespoň se používá index. Získáte však skenování indexu bitmapy namísto normálního skenování indexu, což znamená, že funkce xpath() bude volána mnohokrát.
Udělejme malou kontrolu :
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
Jak vidíme,
- skenování celé tabulky pomocí count(*) trvá 25 ms
- Extrahování jednoho klíče/hodnoty z hstore znamená malé dodatečné náklady, asi 0,12 µs/řádek
- Extrakce jednoho klíče/hodnoty z xml pomocí xpath zvyšuje náklady, asi 33 µs/řádek
Závěry:
- xml je pomalý (ale každý to ví)
- Pokud chcete do sloupce umístit flexibilní úložiště párů klíč/hodnota, použijte hstore
Vzhledem k tomu, že vaše xml data jsou poměrně velká, budou také toastována (komprimována a uložena mimo hlavní stůl). Díky tomu jsou řádky v hlavní tabulce mnohem menší, a tudíž více řádků na stránku, což snižuje efektivitu skenování bitmapy, protože je nutné znovu zkontrolovat všechny řádky na stránce.
Můžete to však opravit. Z nějakého důvodu má funkce xpath() (která je velmi pomalá, protože zpracovává xml) stejnou cenu (1 jednotka) jako řekněme celočíselný operátor "+"...
update pg_proc set procost=1000 where proname='xpath';
Možná budete muset upravit hodnotu nákladů. Když jsou mu poskytnuty správné informace, plánovač ví, že xpath je pomalý a vyhne se skenování indexu bitmapy, místo toho použije skenování indexu, které nepotřebuje znovu kontrolovat podmínku pro všechny řádky na stránce.
Všimněte si, že to nevyřeší problém s odhady řádků. Protože nemůžete analyzovat vnitřek xml (nebo hstore), získáte výchozí odhady pro počet řádků (zde 500). Takže plánovač se může úplně mýlit a zvolit katastrofický plán, pokud se jedná o nějaké spoje. Jediným řešením je použití správných sloupců.