Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Penyetelan Performa Lutut:Penggunaan Tabel Sementara yang Salah

Dalam kelanjutan seri "penyetelan performa spontan" ini, saya ingin membahas empat masalah umum yang saya lihat dengan menggunakan tabel sementara. Salah satu dari masalah ini dapat melumpuhkan beban kerja, sehingga perlu diketahui dan dicari di lingkungan Anda.

Masalah 1:Menggunakan Tabel Sementara Jika Tidak Dibutuhkan

https://www.flickr. com/photos/tea_time/3890677277/

Tabel sementara memiliki berbagai kegunaan (mungkin yang paling umum adalah untuk menyimpan kumpulan hasil antara untuk digunakan nanti), tetapi Anda harus ingat bahwa ketika Anda memasukkan tabel sementara ke dalam kueri, Anda mengganggu aliran data melalui pemroses kueri.

Pikirkan populasi tabel sementara sebagai perhentian yang sulit, karena ada kueri (sebut saja produser) untuk menghasilkan set hasil antara, yang kemudian disimpan dalam tabel sementara di tempdb, dan kemudian kueri berikutnya (sebut saja itu konsumen) harus membaca data dari tabel sementara lagi.

Saya sering menemukan bahwa beberapa bagian dari beban kerja benar-benar berkinerja lebih baik ketika tabel sementara benar-benar dihapus, sehingga data mengalir dari bagian produsen kueri ke bagian konsumen dari kueri tanpa harus bertahan di tempdb, dan pengoptimal kueri dapat menghasilkan rencana keseluruhan yang lebih optimal.

Anda sekarang mungkin berpikir, "jadi mengapa seseorang menggunakan tabel sementara jika itu membuat segalanya lebih lambat?" - dan memang begitu! Dalam kasus seperti itu, saya menemukan bahwa penggunaan tabel sementara telah dilembagakan dalam tim pengembangan; seseorang menemukan bahwa menggunakan tabel sementara meningkatkan kinerja bertahun-tahun yang lalu, sehingga tabel sementara menjadi pilihan desain default.

Ini bisa menjadi hal yang sulit untuk diubah, terutama jika Anda memiliki pengembang atau manajer senior yang yakin bahwa tabel sementara harus selalu digunakan. Hal sederhana untuk dicoba adalah memilih kueri yang mahal (misalnya, kueri yang sudah berjalan lama, atau kueri yang dijalankan berkali-kali per detik) dan menghapus satu atau beberapa tabel sementara untuk melihat apakah kinerja meningkat tanpanya. Dan jika demikian, ada bukti Anda untuk menunjukkan orang-orang yang keras kepala!

Masalah 2:Kurangnya Pemfilteran Saat Mengisi Tabel Sementara

Meskipun Anda tidak dapat menghapus tabel sementara, Anda mungkin dapat meningkatkan performa secara drastis dengan memastikan bahwa kode yang mengisi tabel sementara memfilter data yang diambil dari tabel sumber dengan benar.

Saya telah kehilangan hitungan berapa kali saya melihat tabel sementara diisi dengan kode yang dimulai sebagai SELECT * , menyertakan beberapa gabungan tak terbatas, dan tidak memiliki klausa WHERE, lalu kueri selanjutnya yang menggunakan tabel sementara hanya menggunakan beberapa kolom dan memiliki klausa WHERE untuk mengurangi jumlah baris.

Saya ingat satu kasus di mana tabel sementara dalam prosedur tersimpan mengumpulkan data senilai 15 tahun dari database utama, dan kemudian hanya data tahun ini yang digunakan. Ini berulang kali menyebabkan tempdb tumbuh hingga kehabisan ruang pada volume disk, dan prosedur tersimpan akan gagal.

Setiap kali Anda mengisi tabel sementara, hanya gunakan kolom tabel sumber yang diperlukan, dan hanya gunakan baris yang diperlukan – yaitu, dorong predikat filter ke atas ke dalam kode populasi tabel sementara. Ini tidak hanya akan menghemat ruang di tempdb, tetapi juga akan menghemat banyak waktu karena tidak perlu menyalin data yang tidak diperlukan dari tabel sumber (dan berpotensi menghilangkan kebutuhan untuk membaca halaman database sumber dari disk).

Masalah 3:Pengindeksan Tabel Sementara Salah

Sama seperti tabel biasa, Anda hanya boleh membuat indeks yang benar-benar akan digunakan oleh kode kueri selanjutnya untuk membantu kinerja kueri. Saya telah melihat banyak kasus di mana ada indeks nonclustered per kolom tabel sementara, dan indeks kolom tunggal yang dipilih tanpa menganalisis kode selanjutnya seringkali tidak berguna. Sekarang gabungkan indeks nonclustered yang tidak berguna dengan kurangnya pemfilteran saat mengisi tabel sementara, dan Anda memiliki resep untuk tempdb yang sangat besar.

Juga, secara umum, lebih cepat membuat indeks setelah tabel diisi. Ini memberikan bonus tambahan bahwa indeks akan memiliki statistik yang akurat, yang selanjutnya dapat membantu kueri karena pengoptimal kueri akan dapat melakukan estimasi kardinalitas yang akurat.

Memiliki banyak indeks nonclustered yang tidak digunakan tidak hanya membuang-buang ruang disk, tetapi juga waktu yang dibutuhkan untuk membuatnya. Jika ini ada dalam kode yang sering dijalankan, menghapus indeks yang tidak diperlukan yang dibuat setiap kali kode dijalankan dapat berdampak signifikan pada kinerja secara keseluruhan.

Masalah 4:Pertentangan Latch tempdb

Sangat umum untuk ada hambatan penguncian di tempdb yang dapat ditelusuri kembali ke penggunaan tabel sementara. Jika ada banyak koneksi bersamaan yang menjalankan kode yang membuat dan menghapus tabel sementara, akses ke bitmap alokasi database di memori dapat menjadi hambatan yang signifikan.

Ini karena hanya satu utas pada satu waktu yang dapat mengubah bitmap alokasi untuk menandai halaman (dari tabel temp) sebagai dialokasikan atau tidak dialokasikan, sehingga semua utas lainnya harus menunggu, mengurangi throughput beban kerja. Meskipun ada cache tabel sementara sejak SQL Server 2005, ukurannya tidak terlalu besar, dan ada batasan kapan tabel sementara dapat di-cache (misalnya hanya jika ukurannya kurang dari 8 MB).

Cara tradisional untuk mengatasi masalah ini adalah dengan menggunakan trace flag 1118 dan beberapa file data tempdb (lihat posting blog ini untuk info lebih lanjut), tetapi hal lain yang perlu dipertimbangkan adalah menghapus tabel sementara sama sekali!

Ringkasan

Tabel sementara bisa sangat berguna, tetapi sangat mudah dan sering digunakan secara tidak benar. Setiap kali Anda menulis (atau meninjau kode) yang menggunakan tabel sementara, pertimbangkan hal berikut:

  • Apakah tabel sementara ini benar-benar dibutuhkan ?
  • Apakah kode yang mengisi tabel menggunakan pemfilteran yang benar untuk membatasi ukuran tabel sementara?
  • Apakah indeks dibuat setelah populasi tabel (secara umum) dan apakah indeks yang digunakan dengan kode nanti?

Paul White memiliki beberapa posting bagus (di sini dan di sini) tentang penggunaan objek sementara dan penyimpanan cache yang saya sarankan untuk dibaca juga.

Dan satu hal terakhir, jika Anda memutuskan untuk tidak menggunakan tabel sementara, jangan hanya menggantinya dengan variabel tabel, ekspresi tabel umum, atau kursor (semuanya adalah cara umum yang dicoba orang untuk "mengoptimalkan" tabel). tabel sementara) – temukan cara paling efisien untuk (kembali) menulis kode – tidak ada jawaban "satu ukuran cocok untuk semua".

Sampai jumpa lagi, selamat memecahkan masalah!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Lanjutan:LINTAS BERLAKU dan BERLAKU LUAR

  2. Menggunakan Dependensi Modul, Bagian 2

  3. Alasan Lain untuk Menghindari sp_updatestats

  4. 3 Statistik I/O Buruk yang Menunda Kinerja Kueri SQL

  5. Kejutan dan Asumsi Kinerja :STRING_SPLIT()