Kinerja Prosedur Pemicu vs Disimpan di MySQL


11

Sebuah posting di sini di DBA.StackExchange ( Apa praktik terbaik bagi pemicu untuk mempertahankan nomor revisi pada catatan? ) Telah menimbulkan pertanyaan yang menarik (setidaknya, menarik bagi saya) mengenai kinerja di MySQL.

Konteksnya adalah bahwa kami ingin menyisipkan catatan dalam tabel untuk setiap baris yang diperbarui. Sebelum baris diperbarui, kami ingin menyimpan nilai sebelumnya dan kemudian menambah salah satu kolom (kolom "versi").

Jika kita melakukan ini di dalam pemicu, itu bekerja dengan baik. Untuk MySQL, pemicunya adalah baris demi baris , jadi itu akan menjadi solusi yang mudah. Pilih data yang saat ini ada di tabel, masukkan ke dalam tabel logging, dan perbarui kolom "versi" di data baru.

Namun, dimungkinkan untuk memindahkan logika ini ke prosedur tersimpan. Jika Anda melakukannya, Anda sedang melakukan penyisipan, kemudian menambahkan kolom "versi" di tabel. Semuanya akan diatur berdasarkan.

Jadi, ketika datang untuk melakukan insert ini, apakah ini lebih performant untuk menggunakan pendekatan prosedur tersimpan berbasis set atau pendekatan berbasis pemicu?

Pertanyaan ini untuk MySQL (karena memiliki pemicu baris-demi-baris), meskipun bisa diterapkan ke DBMS pemicu baris-demi-baris lainnya.


1
Satu hal yang perlu diingat sehubungan dengan mendorong logika versi ke prosedur yang tersimpan - seberapa punuk Anda akan ketika seseorang, entah bagaimana langsung menulis ke meja melewati mekanisme audit Anda?
billinkc

Saya setuju. Tetapi di ujung lain dari skala, mungkin Anda ingin dengan sengaja memotong logging ini dalam keadaan tertentu. Tentu saja, itu pertanyaan yang sama sekali berbeda . Saya benar-benar hanya ingin tahu tentang implikasi kinerja.
Richard

Jawaban:


7

Demi kesederhanaan, pemicu adalah cara untuk menerapkan segala jenis pelacakan perubahan database. Namun, Anda perlu mengetahui apa yang terjadi di bawah tenda saat Anda menggunakan pemicu.

Menurut Pemrograman Prosedur yang Disimpan MySQL , halaman 256 di bawah kepala "Trigger Overhead" mengatakan yang berikut:

Penting untuk diingat bahwa, karena kebutuhan, pemicu menambah overhead pada pernyataan DML yang mereka terapkan. jumlah aktual overhead akan tergantung pada sifat pemicu, tetapi --- karena semua pemicu MySQL mengeksekusi UNTUK SETIAP BARIS --- overhead dapat dengan cepat terakumulasi untuk pernyataan yang memproses sejumlah besar baris. Karena itu Anda harus menghindari menempatkan pernyataan SQL mahal atau kode prosedural dalam pemicu.

Penjelasan lebih lanjut tentang overhead pemicu diberikan pada halaman 529-531. Titik kesimpulan dari bagian itu menyatakan sebagai berikut:

Pelajaran di sini adalah ini: karena kode pemicu akan dieksekusi sekali untuk setiap baris yang dipengaruhi oleh pernyataan DML, pemicu dapat dengan mudah menjadi faktor paling signifikan dalam kinerja DML. Kode di dalam tubuh pemicu harus seringan mungkin dan - khususnya - pernyataan SQL apa pun dalam pemicu harus didukung oleh indeks bila memungkinkan.

Tidak disebutkan dalam buku ini adalah faktor lain ketika menggunakan pemicu: Ketika datang untuk mengaudit logging, harap perhatikan apa yang Anda masukkan data. Saya mengatakan ini karena jika Anda memilih untuk masuk ke tabel MyISAM, setiap INSERT ke dalam tabel MyISAM menghasilkan kunci tabel penuh selama INSERT. Ini bisa menjadi penghambat serius dalam lingkungan lalu lintas tinggi, transaksi tinggi. Selain itu, jika pemicu bertentangan dengan tabel InnoDB dan Anda mencatat perubahan di MyISAM dari dalam pemicu, ini akan secara diam-diam menonaktifkan kepatuhan ACID (yaitu, mengurangi transaksi blok menjadi perilaku autocommit), yang tidak dapat dibatalkan.

Saat menggunakan pemicu pada tabel InnoDB dan mencatat perubahan

  • Tabel yang Anda masuki juga InnoDB
  • Anda telah menonaktifkan otomatis
  • Anda mengatur MULAI TRANSAKSI ... KOMIT / ROLLBACK blok secara menyeluruh

Dengan cara ini, log audit dapat mengambil manfaat dari COMMIT / ROLLBACK seperti tabel utama.

Mengenai menggunakan prosedur tersimpan, Anda harus dengan susah payah memanggil prosedur tersimpan di setiap titik DML terhadap tabel yang dilacak. Orang bisa dengan mudah melewatkan perubahan logging di hadapan puluhan ribu baris kode aplikasi. Menempatkan kode tersebut di pemicu menghilangkan menemukan semua pernyataan DML tersebut.

CAVEAT

Bergantung pada seberapa kompleks pemicunya, masih bisa menjadi hambatan. Jika Anda ingin mengurangi hambatan dalam pendataan audit, ada sesuatu yang bisa Anda lakukan. Namun, itu akan membutuhkan sedikit perubahan infrastruktur.

Menggunakan perangkat keras komoditas, buat dua Server DB lagi

Server ini akan mengurangi write I / O pada database utama (MD) karena audit logging. Inilah cara Anda dapat mencapainya:

Langkah 01) Nyalakan binary logging di database utama.

Langkah 02) Menggunakan server yang tidak mahal, setup MySQL (versi yang sama dengan MD) dengan pencatatan biner diaktifkan. Ini akan menjadi DM. Atur replikasi dari MD ke DM.

Langkah 03) Menggunakan server murah kedua, setup MySQL (versi yang sama dengan MD) dengan biner logging dinonaktifkan. Siapkan setiap tabel audit untuk menggunakan --replicate-do-table . Ini akan menjadi AU. Atur replikasi dari DM ke AU.

Langkah 04) mysqldump struktur tabel dari MD dan memuatnya ke DM dan AU.

Langkah 05) Konversikan semua tabel audit dalam MD untuk menggunakan mesin penyimpanan BLACKHOLE

Langkah 06) Ubah semua tabel dalam DM dan AU untuk menggunakan mesin penyimpanan BLACKHOLE

Langkah 07) Konversikan semua tabel audit dalam AU untuk menggunakan mesin penyimpanan MyISAM

Ketika selesai

  • DM akan mereplikasi dari MD dan merekam hal-hal hanya dalam log binernya
  • Dengan filter --replicate-do-table di semua tabel audit, AU akan mereplikasi dari DM

Apa yang dilakukan adalah menyimpan info audit pada server DB yang terpisah dan juga mengurangi degradasi penulisan I / O yang biasanya dimiliki MD.


Jawaban yang luar biasa +++ 1
b_dubb

1

Berikut adalah pendekatan untuk melakukan pembaruan ini secara massal.

Untuk contoh ini

  • table_A memiliki id KUNCI UTAMA
  • Anda membuat tabel bernama table_A_Keys2Update dengan hanya id sebagai PRIMARY KEY
  • Anda mengisi table_A_Keys2Perbarui withs id dari table_A yang Anda tahu harus diperbarui

Untuk membuat table_A_Keys2Update lakukan hal berikut:

CREATE TABLE table_A_Keys2Update SELECT id FROM table_A;
ALTER TABLE table_A_Keys2Update ADD PRIMARY KEY (id);

Setelah Anda mengisi table_A_Keys2Update dengan id yang nomor revisi-nya perlu ditambah, lakukan UPDATE BERGABUNG berikut ini untuk menambah jumlah revisi semua baris yang id-nya ada di table_A dan table_A_Keys2Update:

UPDATE table_A A INNER JOIN table_A_Keys2Update B USING (id)
SET A.revision = A.revision + 1;

Kueri satu baris ini dapat menggantikan pemicu dan prosedur tersimpan.

Secara opsional, Anda dapat menempatkan kueri yang satu ini dalam prosedur tersimpan dan memanggilnya jika diinginkan.


Ini benar-benar Sisipan yang membuat saya penasaran. Jika Anda MASUK KE audit, PILIH <apa pun> DARI <primary_table> WHERE <parameter dari prosedur tersimpan> Anda bisa melakukan penyisipan dalam jumlah besar. Dalam pemicu, Anda hanya akan MASUKKAN NILAI audit <data dari baris yang diperbarui> . Jadi, akankah baris tunggal, baris demi baris disisipkan lebih cepat daripada insert massal?
Richard

Demi kesederhanaan, pemicunya akan jauh lebih baik 1) asalkan primary_table tidak pernah mengalami sisipan bulks di tengah-tengah masa puncak, 2) info audit harus dibaca sesuai permintaan pada saat tertentu, dan 3) situs Anda perdagangan rendah.
RolandoMySQLDBA
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.