Chà, ít nhất chỉ mục được sử dụng. Tuy nhiên, bạn nhận được một bản quét chỉ mục bitmap thay vì quét chỉ mục bình thường, có nghĩa là hàm xpath () sẽ được gọi rất nhiều lần.
Hãy kiểm tra một chút:
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
Như chúng ta có thể thấy,
- quét toàn bộ bảng với số đếm (*) mất 25 mili giây
- trích xuất một khóa / giá trị từ một hstore sẽ làm tăng thêm một khoản chi phí nhỏ, khoảng 0,12 µs / hàng
- trích xuất một khóa / giá trị từ xml bằng xpath sẽ làm tăng thêm chi phí, khoảng 33 µs / hàng
Kết luận:
- xml chậm (nhưng mọi người đều biết điều đó)
- nếu bạn muốn đặt kho khóa / giá trị linh hoạt trong một cột, hãy sử dụng hstore
Ngoài ra, vì dữ liệu xml của bạn khá lớn nên nó sẽ được nướng (nén và lưu trữ ngoài bảng chính). Điều này làm cho các hàng trong bảng chính nhỏ hơn nhiều, do đó nhiều hàng hơn trên mỗi trang, điều này làm giảm hiệu quả của việc quét bitmap vì tất cả các hàng trên một trang phải được kiểm tra lại.
Bạn có thể sửa lỗi này. Vì lý do nào đó, hàm xpath () (rất chậm, vì nó xử lý xml) có cùng chi phí (1 đơn vị) như toán tử số nguyên "+" ...
update pg_proc set procost=1000 where proname='xpath';
Bạn có thể cần phải điều chỉnh giá trị chi phí. Khi được cung cấp thông tin phù hợp, người lập kế hoạch biết xpath chậm và sẽ tránh quét chỉ mục bitmap, thay vào đó sử dụng quét chỉ mục, không cần kiểm tra lại điều kiện cho tất cả các hàng trên trang.
Lưu ý rằng điều này không giải quyết vấn đề ước tính hàng. Vì bạn không thể PHÂN TÍCH bên trong xml (hoặc hstore), bạn sẽ nhận được ước tính mặc định cho số hàng (ở đây, 500). Vì vậy, người lập kế hoạch có thể hoàn toàn sai lầm và chọn một kế hoạch thảm khốc nếu có sự tham gia của một số người. Giải pháp duy nhất cho điều này là sử dụng các cột thích hợp.