PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Indeks Postgresql pada ekspresi xpath tidak memberikan kecepatan

Yah, setidaknya indeks digunakan. Anda mendapatkan pemindaian indeks bitmap alih-alih pemindaian indeks normal, yang berarti fungsi xpath() akan dipanggil berkali-kali.

Mari kita lakukan sedikit pemeriksaan :

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

Seperti yang kita lihat,

  • memindai seluruh tabel dengan hitungan(*) membutuhkan waktu 25 md
  • mengekstrak satu kunci/nilai dari hstore menambahkan sedikit biaya tambahan, sekitar 0,12 s/baris
  • mengekstrak satu kunci/nilai dari xml menggunakan xpath menambah biaya yang sangat besar, sekitar 33 s/baris

Kesimpulan :

  • xml lambat (tapi semua orang tahu itu)
  • jika Anda ingin meletakkan penyimpanan kunci/nilai fleksibel di kolom, gunakan hstore

Juga karena data xml Anda cukup besar, itu akan dipanggang (dikompresi dan disimpan dari tabel utama). Hal ini membuat baris dalam tabel utama jauh lebih kecil, sehingga lebih banyak baris per halaman, yang mengurangi efisiensi pemindaian bitmap karena semua baris pada halaman harus diperiksa ulang.

Anda dapat memperbaiki ini sekalipun. Untuk beberapa alasan fungsi xpath() (yang sangat lambat, karena menangani xml) memiliki biaya yang sama (1 unit) seperti yang dikatakan, operator bilangan bulat "+"...

update pg_proc set procost=1000 where proname='xpath';

Anda mungkin perlu mengubah nilai biaya. Saat diberi info yang benar, perencana mengetahui bahwa xpath lambat dan akan menghindari pemindaian indeks bitmap, menggunakan pemindaian indeks, yang tidak perlu memeriksa ulang kondisi untuk semua baris pada halaman.

Perhatikan bahwa ini tidak menyelesaikan masalah estimasi baris. Karena Anda tidak dapat MENGANALISIS bagian dalam xml (atau hstore), Anda mendapatkan perkiraan default untuk jumlah baris (di sini, 500). Jadi, perencana mungkin sepenuhnya salah dan memilih rencana bencana jika beberapa gabungan terlibat. Satu-satunya solusi untuk ini adalah dengan menggunakan kolom yang tepat.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sekuel menyimpan banyak ke banyak

  2. Bagaimana cara terhubung ke server PostgreSQL melalui JDBC di Android?

  3. Postgres - menggabungkan dua kolom menjadi satu item

  4. Mengganti teks yang cocok dengan regex dengan versi huruf besar di Postgresql

  5. Gabungan ATAU kueri SQL (kueri #1 dengan WITH) dan (kueri #2) dengan COUNT() pengecualian