Kembali pada tahun 2015, saya memutakhirkan database Oracle 11.2.0.4 kami ke 12.1.0.2 dan mengalami beberapa masalah kinerja terkait dengan penggunaan GTT kami. Saya membuat blog tentang masalah-masalah itu di sini.
Inti dari masalah yang saya coba pecahkan adalah bahwa perubahan perilaku dalam 12c mengarah ke statistik penyimpanan Oracle bahwa GTT memiliki baris nol ketika tidak. Statistik yang menunjukkan jumlah baris sama dengan nol mengarah ke pemindaian tabel lengkap dan produk kartesius pada kueri yang melibatkan GTT. Seperti yang saya nyatakan dalam posting blog itu, kami menggunakan DBMS_STATS.SET_TABLE_STATS setelah kami mengisi tabel dengan data sehingga setiap sesi akan memiliki statistik yang tepat untuk sampai pada rencana eksekusi yang lebih baik.
Setelah kami meningkatkan ke Oracle 19c, kami mulai melihat masalah kinerja lain yang terkait dengan GTT. Kueri yang menggunakan GTT mulai menunggu pada acara tunggu “pin kursor:S wait on X”. Ini bisa jadi merupakan perubahan perilaku dengan versi Oracle yang baru, tetapi bisa juga karena pengembang kami lebih sering menggunakan GTT dalam kode kami dan tidak ada hubungannya dengan versi baru.
Untuk kueri yang terlibat dalam acara tunggu Pin Kursor, saya melihat sejumlah besar versi pernyataan SQL di Kumpulan Bersama. Ketika saya menanyakan V$SQL_SHARED_CURSOR, saya menemukan bahwa PURGED_CURSOR='Y' untuk pernyataan SQL ini. Kursor menjadi tidak valid.
Saat meneliti masalah ini, saya menemukan bahwa apa yang terjadi adalah bahwa setiap kali kami memanggil DBMS_STATS.SET_TABLE_STATS untuk mendapatkan statistik berbasis sesi di GTT, itu membatalkan semua pernyataan SQL yang menggunakan GTT itu. Oleh karena itu menunggu. Penantiannya tidak lama sehingga banyak pengguna akhir bahkan tidak menyadari masalah ini.
Tapi kemudian kami mendapat masalah baru. Saat Anda melakukan panggilan ke SET_TABLE_STATS, Oracle menulis entri ke SYS.WRI$_OPTSTAT_TAB_HISTORY dan Anda dapat melihat nilai yang ditetapkan sesi untuk statistik tabel. Secara default, tabel ini menyimpan riwayat 30 hari. Tabel tumbuh sangat besar dan menghabiskan sebagian besar SYSAUX. Seringkali (setiap jam?) Oracle akan menghapus entri yang berumur lebih dari 30 hari. Pemangkasan rutin tabel ini sekarang berdampak negatif pada kinerja pengguna akhir. Berikut adalah grafik kinerja dari Lighty yang menunjukkan dampak pemangkasan tabel ini:
Semua warna merah menakutkan itu adalah ketika baris lama dihapus dari SYS.WRI$_OPTSTAT_TAB_HISTORY.
Jadi kinerja saya "memperbaiki" lima tahun lalu memperkenalkan masalah kinerja lain. Untuk meningkatkan kinerja, yang saya lakukan adalah membuat statistik bersama di GTT dan berhenti menggunakan statistik sesi. Berikut langkah-langkahnya:
--set prefs to SHARED globally
exec DBMS_STATS.set_global_prefs ( pname => 'GLOBAL_TEMP_TABLE_STATS', pvalue => 'SHARED');
--set the table and index stats
exec dbms_stats.set_table_stats(ownname=>'MY_SCHEMA',tabname=>'MY_GTT_TABLE',numrows=>1000,numblks=>2,avgrlen=>15);
exec dbms_stats.set_index_stats(ownname=>'MY_SCHEMA',indname=>'GTT_INDEX',indlevel=>1,numlblks=>2,numdist=>15,clstfct=>28,numrows=>1000);
-- set prefs back to SESSION
exec DBMS_STATS.set_global_prefs ( pname => 'GLOBAL_TEMP_TABLE_STATS', pvalue => 'SESSION');
-- verify stats set
select num_rows,blocks,last_analyzed,scope
from dba_tab_statistics
where table_name ='MY_GTT_TABLE';
select blevel,leaf_blocks,distinct_keys,num_rows,clustering_factor,last_analyzed,scope
from dba_ind_statistics
where index_name='GTT_INDEX' and owner='MY_SCHEMA';
Setelah statistik bersama diterapkan, kami menghapus panggilan ke DBMS_SET_TABLE_STATS dari kode kami.