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

Spring + Hibernate:Penggunaan Memori Cache Rencana Kueri

Saya telah memukul masalah ini juga. Ini pada dasarnya bermuara pada memiliki jumlah variabel nilai dalam klausa IN Anda dan Hibernate mencoba untuk men-cache rencana kueri tersebut.

Ada dua posting blog yang bagus tentang topik ini. Yang pertama:

Menggunakan Hibernate 4.2 dan MySQL dalam proyek dengan query dalam klausa seperti:select t from Thing t where t.id in (?)

Hibernasi menyimpan kueri HQL yang diuraikan ini dalam cache. Khususnya HibernateSessionFactoryImpl memiliki QueryPlanCache dengan queryPlanCache danparameterMetadataCache . Tapi ini terbukti menjadi masalah ketika jumlah parameter untuk in-clause besar dan bervariasi.

Cache ini tumbuh untuk setiap kueri yang berbeda. Jadi kueri dengan 6000parameter ini tidak sama dengan 6001.

Kueri dalam klausa diperluas ke jumlah parameter dalam koleksi. Metadata disertakan dalam rencana kueri untuk setiap parameter dalam kueri, termasuk nama yang dihasilkan seperti x10_, x11_ , dll.

Bayangkan 4000 variasi berbeda dalam jumlah jumlah parameter dalam klausa, masing-masing dengan rata-rata 4000 parameter. Metadata kueri untuk setiap parameter dengan cepat bertambah di memori, memenuhi tumpukan, karena tidak dapat dikumpulkan dari sampah.

Ini berlanjut hingga semua variasi berbeda dalam jumlah parameter kueri di-cache atau JVM kehabisan memori heap dan mulai melemparjava.lang.OutOfMemoryError:Java heap space.

Menghindari dalam klausa adalah sebuah opsi, serta menggunakan ukuran koleksi tetap untuk parameter (atau setidaknya ukuran yang lebih kecil).

Untuk mengonfigurasi ukuran maksimum cache paket kueri, lihat propertihibernate.query.plan_cache_max_size , default ke 2048 (mudah terlalu besar untuk kueri dengan banyak parameter).

Dan kedua (juga dirujuk dari yang pertama):

Hibernasi secara internal menggunakan cache yang memetakan pernyataan HQL (asstring) ke rencana kueri. Cache terdiri dari peta terbatas yang dibatasi secara default hingga 2048 elemen (dapat dikonfigurasi). Semua kueri HQL dimuat melalui cache ini. Jika terjadi kesalahan, entri tersebut secara otomatis ditambahkan ke cache. Ini membuatnya sangat rentan terhadap thrashing - skenario di mana kami terus-menerus memasukkan entri baru ke dalam cache tanpa pernah menggunakannya kembali dan dengan demikian mencegah cache membawa keuntungan kinerja apa pun (bahkan menambahkan beberapa overhead manajemen cache). Untuk memperburuk keadaan, sulit untuk mendeteksi situasi ini secara kebetulan - Anda harus membuat profil cache secara eksplisit untuk mengetahui bahwa Anda memiliki masalah di sana. Saya akan mengatakan beberapa patah kata tentang bagaimana ini bisa dilakukan nanti.

Jadi cache thrashing dihasilkan dari kueri baru yang dihasilkan dengan kecepatan tinggi. Hal ini dapat disebabkan oleh banyak masalah. Dua yang paling umum yang saya lihat adalah - bug dalam hibernasi yang menyebabkan parameter dirender dalam pernyataan JPQL alih-alih dilewatkan sebagai parameter dan penggunaan klausa "dalam".

Karena beberapa bug yang tidak jelas dalam hibernasi, ada situasi ketika parameter tidak ditangani dengan benar dan dirender ke dalam kueri JPQL (sebagai contoh lihat HHH-6280). Jika Anda memiliki kueri yang terpengaruh oleh cacat tersebut dan dijalankan dengan kecepatan tinggi, kueri tersebut akan mengosongkan cache rencana kueri Anda karena setiap kueri JPQL yang dihasilkan hampir unik (berisi ID entitas Anda misalnya).

Masalah kedua terletak pada cara hibernasi memproses kueri dengan klausa "dalam" (mis. Untuk setiap jumlah parameter yang berbeda dalam klausa "dalam", hibernasi akan menghasilkan kueri yang berbeda - mis.select x from Person x where x.company.id in (:id0_) untuk 1 parameter,select x from Person x where x.company.id in (:id0_, :id1_) untuk 2parameter dan seterusnya. Semua kueri ini dianggap berbeda, sejauh menyangkut cache rencana kueri, menghasilkan lagi cachethrashing. Anda mungkin dapat mengatasi masalah ini dengan menulis kelas utilitas untuk menghasilkan hanya sejumlah parameter tertentu - mis. 1,10, 100, 200, 500, 1000. Jika Anda, misalnya, melewati 22 parameter, itu akan mengembalikan daftar 100 elemen dengan 22 parameter termasuk init dan 78 parameter sisanya disetel ke nilai yang tidak mungkin (misalnya -1untuk ID digunakan untuk kunci asing). Saya setuju bahwa ini adalah peretasan yang buruk tetapi bisa menyelesaikan pekerjaan. Akibatnya, Anda hanya akan memiliki paling banyak 6 kueri unik di cache Anda dan dengan demikian mengurangi thrashing.

Jadi bagaimana Anda mengetahui bahwa Anda memiliki masalah? Anda dapat menulis beberapa kode tambahan dan mengekspos metrik dengan jumlah entri dalam cache mis. melalui JMX, menyetel logging dan menganalisis log, dll. Jika Anda tidak ingin (atau tidak dapat) memodifikasi aplikasi, Anda dapat membuang heap dan menjalankan kueri OQL ini terhadapnya (misalnya menggunakan mat):SELECT l.query.toString() FROM INSTANCEOF org.hibernate.engine.query.spi.QueryPlanCache$HQLQueryPlanKey l . Ini akan menampilkan semua kueri yang saat ini berada di cache rencana kueri apa pun di heap Anda. Seharusnya cukup mudah untuk mengetahui apakah Anda terpengaruh oleh salah satu masalah yang disebutkan di atas.

Sejauh dampak kinerja berjalan, sulit untuk mengatakan karena tergantung pada terlalu banyak faktor. Saya telah melihat kueri yang sangat sepele yang menyebabkan 10-20 msof overhead dihabiskan dalam membuat rencana kueri HQL baru. Secara umum, jika ada cache di suatu tempat, pasti ada alasan bagus untuk itu - kesalahan mungkin mahal sehingga Anda harus berusaha menghindari kesalahan sebanyak mungkin. Last but not least, database Anda juga harus menangani sejumlah besar pernyataan SQL unik - menyebabkannya menguraikannya dan mungkin membuat rencana eksekusi yang berbeda untuk setiap pernyataan tersebut.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara membersihkan dan menginstal ulang postgresql secara menyeluruh di ubuntu?

  2. Membuat Database PostgreSQL

  3. DROP FUNCTION tanpa mengetahui jumlah/jenis parameter?

  4. Daftar Periksa Kepatuhan SOx untuk PostgreSQL

  5. Paralelisme datang ke VAKUM