CREATE TABLE classes ( id integer NOT NULL, name text, is_closed boolean, obects_count integer, CONSTRAINT classes_pk PRIMARY KEY (id ) ); CREATE TABLE objects ( id integer NOT NULL, body xml, id_classes integer, CONSTRAINT objects_pk PRIMARY KEY (id ), CONSTRAINT classes_objects FOREIGN KEY (id_classes) REFERENCES classes (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ); CREATE INDEX fki_classes_objects ON objects USING btree (id_classes );
INSERT INTO classes( id, name, is_closed, obects_count) VALUES (1, 'customers', FALSE, 0); INSERT INTO classes( id, name, is_closed, obects_count) VALUES (2, 'orders', FALSE, 0);
CREATE OR REPLACE FUNCTION random(numeric, numeric) RETURNS numeric AS $BODY$ SELECT ($1 + ($2 - $1) * random())::numeric; $BODY$ LANGUAGE sql VOLATILE COST 100; CREATE OR REPLACE FUNCTION random_string(length integer) RETURNS text AS $BODY$ declare chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'; result text := ''; i integer := 0; begin if length < 0 then raise exception 'Given length cannot be less than 0'; end if; for i in 1..length loop result := result || chars[1+random()*(array_length(chars, 1)-1)]; end loop; return result; end; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DO $$ DECLARE customer_pk integer; order_pk integer; BEGIN FOR i in 1..10000 LOOP customer_pk := nextval('objects_id_seq'); order_pk := nextval('objects_id_seq'); insert into objects (body, id_classes) values(( '<Customers> <Customer> <ID>' || customer_pk || '</ID> <Name>' || random_string('10') || '</Name> <Partners>' || random_string('10') || '</Partners> </Customer> </Customers>')::xml, 1); for j in 1..5 LOOP insert into objects (body, id_classes) values(( '<Orders> <Order> <ID>' || order_pk || '</ID> <Customer_id>' || customer_pk || '</Customer_id> <Cost>' || random(1, 1000) || '</Cost> </Order> </Orders>')::xml, 2); end loop; END LOOP; END$$;
explain select max(((xpath('/Orders/Order/Cost/text()', O.body))[1])::text::float) as cost_of_order from Objects O where O.id_classes = 2;
/* Aggregate (cost=2609.10..2609.11 rows=1 width=32) -> Seq Scan on objects o (cost=0.00..2104.50 rows=50460 width=32) Filter: (id_classes = 2) */
create index obj_orders_cost_idx on objects using btree (((xpath('/Orders/Order/Cost/text()', body))[1]::text::float));
/* Result (cost=0.15..0.16 rows=1 width=0) InitPlan 1 (returns $0) -> Limit (cost=0.00..0.15 rows=1 width=32) -> Index Scan Backward using obj_orders_cost_idx on objects o (cost=0.00..7246.26 rows=50207 width=32) Index Cond: ((((xpath('/Orders/Order/Cost/text()'::text, body, '{}'::text[]))[1])::text)::double precision IS NOT NULL) Filter: (id_classes = 2) */
explain select (xpath('/Customers/Customer/Name/text()', C.body))[1] as customer , (xpath('/Orders/Order/Cost/text()', O.body))[1] as cost_of_order from objects C , objects O where C.id_classes = 1 and O.id_classes = 2 and (xpath('/Orders/Order/Customer_id/text()', O.body))[1]::text::int = (xpath('/Customers/Customer/ID/text()', C.body))[1]::text::int and ((xpath('/Customers/Customer/ID/text()' ,C.body))[1])::text::int between 1997585 and 1997595;
/* Hash Join (cost=1873.57..6504.85 rows=12867 width=64) Hash Cond: ((((xpath('/Orders/Order/Customer_id/text()'::text, o.body, '{}'::text[]))[1])::text)::integer = (((xpath('/Customers/Customer/ID/text()'::text, c.body, '{}'::text[]))[1])::text)::integer) -> Seq Scan on objects o (cost=0.00..2104.50 rows=50460 width=32) Filter: (id_classes = 2) -> Hash (cost=1872.93..1872.93 rows=51 width=32) -> Bitmap Heap Scan on objects c (cost=196.38..1872.93 rows=51 width=32) Recheck Cond: (id_classes = 1) Filter: (((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer >= 1997585) AND ((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer <= 1997595)) -> Bitmap Index Scan on fki_classes_objects (cost=0.00..196.37 rows=10140 width=0) Index Cond: (id_classes = 1) */
create index obj_customers_id_idx on objects using btree (((xpath('/Customers/Customer/ID/text()', body))[1]::text::int)); create index obj_orders_id_idx on objects using btree (((xpath('/Orders/Order/ID/text()', body))[1]::text::int)); create index obj_orders_customerid_idx on objects using btree (((xpath('/Orders/Order/Customer_id/text()', body))[1]::text::int));
/* Hash Join (cost=380.52..5011.80 rows=12867 width=64) Hash Cond: ((((xpath('/Orders/Order/Customer_id/text()'::text, o.body, '{}'::text[]))[1])::text)::integer = (((xpath('/Customers/Customer/ID/text()'::text, c.body, '{}'::text[]))[1])::text)::integer) -> Seq Scan on objects o (cost=0.00..2104.50 rows=50460 width=32) Filter: (id_classes = 2) -> Hash (cost=379.88..379.88 rows=51 width=32) -> Bitmap Heap Scan on objects c (cost=204.00..379.88 rows=51 width=32) Recheck Cond: (((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer >= 1997585) AND ((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer <= 1997595) AND (id_classes = 1)) -> BitmapAnd (cost=204.00..204.00 rows=51 width=0) -> Bitmap Index Scan on obj_customers_id_idx (cost=0.00..7.35 rows=303 width=0) Index Cond: (((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer >= 1997585) AND ((((xpath('/Customers/Customer/ID/text()'::text, body, '{}'::text[]))[1])::text)::integer <= 1997595)) -> Bitmap Index Scan on fki_classes_objects (cost=0.00..196.37 rows=10140 width=0) Index Cond: (id_classes = 1) */
Source: https://habr.com/ru/post/164803/