Bagaimana cara menggunakan insert delay dengan mesin InnoDB dan menggunakan lebih sedikit koneksi untuk memasukkan pernyataan?

10

Saya sedang mengerjakan aplikasi yang melibatkan banyak penulisan basis data, kira-kira ~ 70% sisipan dan 30% dibaca. Rasio ini juga akan mencakup pembaruan yang saya anggap satu baca dan satu tulis. Melalui pernyataan penyisipan, beberapa klien memasukkan data ke dalam basis data melalui pernyataan menyisipkan di bawah ini:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

Pertanyaannya adalah apakah saya harus menggunakan insert_delay atau menggunakan mekanisme mysqli_multi_query karena pernyataan insert menggunakan ~ 100% cpu di server. Saya menggunakan mesin InnoDB pada database saya sehingga memasukkan yang tertunda tidak mungkin. Penyisipan di server ~ 36k / jam dan 99,89% dibaca, saya juga menggunakan pernyataan pilih di sana mengambil data tujuh kali dalam permintaan tunggal , permintaan ini membutuhkan 150 detik pada server untuk mengeksekusi. Teknik atau mekanisme apa yang bisa saya gunakan untuk tugas ini? Memori server saya adalah 2 gb, apakah saya harus menambah memori? Lihat masalah ini, setiap saran akan berterima kasih kepada saya.

Struktur meja:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

Basis data status saya, ini menunjukkan 41k penyisipan (menulis), yang sangat lambat untuk database saya.

status basis data

Shashank
sumber
Bisakah Anda memberikan definisi tabel? (semua kolom, tipe data, dan indeks)
ypercubeᵀᴹ
Bisakah Anda memberikan cuplikan singkat tentang Anda SHOW FULL PROCESSLISTsaat mengambil 100% cpu? Berapa banyak koneksi yang Anda izinkan vs berapa banyak yang diambil selama waktu ini?
Derek Downey
Silakan jalankan dua pertanyaan ini: SHOW GLOBAL VARIABLES LIKE 'innodb%';dan SELECT VERSION();dan tampilkan hasilnya.
RolandoMySQLDBA
Harap berikan jumlah sisipan per detik yang Anda jalankan.
dabest1
Kode Anda sangat rentan terhadap injeksi SQL. Gunakan pernyataan dan nilai parameter yang disiapkan.
Aaron Brown

Jawaban:

11

Karena Anda memiliki lebih banyak tulisan daripada membaca, saya ingin merekomendasikan yang berikut ini

Penyesuaian yang layak dari InnoDB akan menjadi kuncinya

Buffer Pool ( Diukuran oleh innodb_buffer_pool_size )

Karena InnoDB tidak mendukung INSERT DELAYED , menggunakan Pool Buffer InnoDB besar adalah hal terdekat yang dapat Anda peroleh dengan INSERT DELAYED. Semua DML (INSERT, UPDATE, dan DELETE) akan di-cache di Pool Buffer InnoDB. Informasi transaksional untuk Menulis ditulis segera ke Redo Logs (ib_logfile0, ib_logfile1). Tulisan yang diposting di Buffer Pool secara berkala memerah dari memori ke disk melalui ibdata1 (InsertBuffer untuk Secondary Indexes, Double Write Buffer). Semakin besar Buffer Pool, semakin besar jumlah INSERT yang bisa di-cache. Dalam sistem dengan 8GB atau lebih dari RAM, gunakan 75-80% dari RAM sebagai innodb_buffer_pool_size. Dalam sistem dengan RAM yang sangat sedikit, 25% (untuk mengakomodasi OS).

CAVEAT: Anda dapat mengatur innodb_doublewrite menjadi 0 untuk mempercepat menulis lebih banyak, tetapi dengan risiko integritas data. Anda juga dapat mempercepat dengan menyetel innodb_flush_method ke O_DIRECT untuk mencegah caching InnoDB ke OS.

Redo Logs ( Diukuran oleh innodb_log_file_size )

Secara default, redo log diberi nama ib_logfile0 dan ib_logfile1 dan masing-masing akan berukuran 5MB. Ukurannya harus 25% dari innodb_buffer_pool_size. Jika redo log sudah ada, tambahkan pengaturan baru di my.cnf, matikan mysql, hapus, dan restart mysql .

Buffer Log ( Diukuran oleh innodb_log_buffer_size )

Buffer log menyimpan perubahan dalam RAM sebelum memasukkannya ke dalam redo log. Standarnya adalah 8M. Semakin besar buffer log, semakin sedikit Disk I / O. Hati-hati dengan transaksi yang sangat besar, karena ini dapat memperlambat KOMIT dalam milidetik.

Mengakses Banyak CPU

MySQL 5.5 dan MySQL 5.1 InnoDB Plugin memiliki pengaturan agar InnoDB Storage Engine mengakses beberapa CPU. Berikut adalah opsi yang perlu Anda atur:

  • innodb_thread_concurrency menetapkan batas atas jumlah utas bersamaan yang bisa dibuka oleh InnoDB. Biasanya disarankan untuk mengatur ini adalah (2 X Jumlah CPU) + Jumlah Disk. Tahun lalu, saya belajar secara langsung dari Konferensi NYC Percona bahwa Anda harus menetapkan ini ke 0 untuk memperingatkan InnoDB Storage Engine untuk menemukan jumlah utas terbaik untuk lingkungan tempat ia berjalan.
  • innodb_concurrency_tickets menetapkan jumlah utas yang dapat melewati pemeriksaan konkurensi dengan impunitas. Setelah batas itu tercapai, pengecekan konkurensi thread menjadi norma lagi.
  • innodb_commit_concurrency menetapkan jumlah transaksi bersamaan yang dapat dilakukan. Karena defaultnya adalah 0, tidak menetapkan ini memungkinkan sejumlah transaksi untuk melakukan secara bersamaan.
  • innodb_thread_sleep_delay menetapkan jumlah milidetik yang dapat dinonaktifkan oleh InnoDB sebelum masuk kembali ke antrian InnoDB. Standarnya adalah 10.000 (10 detik).
  • innodb_read_io_threads (atur ini ke 3000) dan innodb_write_io_threads (atur ini ke 7000) (keduanya sejak MySQL 5.1.38) mengalokasikan jumlah utas yang ditentukan untuk membaca dan menulis. Default adalah 4 dan maksimum adalah 64. Tetapkan ini ke 64. Juga, atur innodb_io_capacity menjadi 10000.

Tingkatkan ke MySQL 5.5

Jika Anda memiliki MySQL 5.0, tingkatkan ke MySQL 5.5. Jika Anda memiliki MySQL 5.1.37 atau sebelumnya, tingkatkan ke MySQL 5.5. Jika Anda memiliki MySQL 5.1.38 atau lebih dan ingin tetap di MySQL 5.1, instal Plugin InnoDB. Dengan begitu, Anda dapat memanfaatkan semua CPU untuk InnoDB.

RolandoMySQLDBA
sumber
memori server saya adalah 2GB, jadi menurut memori saya mengatur innodb buffer pool menjadi 500M, dan mencatat file 25% ke pool, juga mengatur buffer log ke 64M. Namun server masih sangat sibuk. Haruskah saya meningkatkan memori? Juga server saya ada di ubuntu 32 bit, jadi maks saya bisa mengatur memori ke 4 GB.
Shashank
Jika server hanya untuk MySQL (tanpa apache, tanpa PHP), maka innodb_buffer_pool_size dapat mencapai 75% dari 2GB, yaitu 1536M. Jika Anda meningkatkan ke 4GB, innodb_buffer_pool_size dapat berupa 3G. File log harus 25% dari kumpulan buffer seperti yang Anda nyatakan.
RolandoMySQLDBA
Server menjalankan apache2, mysql dan php, haruskah saya pergi untuk meningkatkan memori dalam situasi ini atau apakah ada solusi optimal kecuali ke kolam buffer innodb?
Shashank
Orang ini tidak setuju dengan Anda: percona.com/blog/2008/11/21/... Sulit untuk berdebat dengan Percona.
Zenexer
Rolando - sarankan Anda menambahkan jawaban dengan pembaruan untuk 5.6 dan 5.7. Default telah berubah; pengaturan lain tersedia; dll. Mungkin termasuk Percona dan MariaDB dan 8,0 tips.
Rick James
2

INT (2) masih menggunakan 4 byte - mungkin maksud Anda TINYINT UNSIGNED?

Berapa banyak nilai yang berbeda di setno? Jika kecil, KUNCI (setno) tidak akan pernah digunakan. INSERTing harus memperbarui indeks itu; menghapus KUNCI akan mempercepat MASUKKAN beberapa.

CHAR (10) - Apakah flagselalu 10 karakter? Dan di utf8? Mungkin Anda bisa menggunakan flag VARCHAR (10) CHARACTER SET ascii

Batch sisipan Anda - 100 sekaligus akan berjalan 10 kali lebih cepat. (Melampaui 100 masuk ke 'pengembalian berkurang'.)

Berapa nilai autocommit? Apakah Anda membungkus setiap INSERT dalam BEGIN ... COMMIT? Berapa nilai innodb_flush_log_at_trx_commit?

Rick James
sumber
bagaimana saya bisa memasukkan dalam batch jika data dimasukkan melalui sumber eksternal seperti klien yang berbeda dengan nilai yang berbeda .... apakah dapat diandalkan jika saya menggunakan: codemasukkan ke nilai t_name (col1, col2, col3) (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank
1

Siapkan antrian. Aplikasi akan menulis ke dalam antrian 1 baris sekaligus dan kemudian mengambil baris keluar dan memasukkan ke dalam basis data dalam jumlah berdasarkan jumlah baris pada jumlah waktu yang berlalu sejak memasukkan terakhir.

Saya telah melihat di mana mengumpulkan 10.000 sisipan sekaligus adalah yang tercepat, jadi Anda perlu menguji untuk menemukan sweet spot.

Anda bisa membuat sistem antrian sederhana sendiri atau menggunakan yang sudah ada. Berikut adalah beberapa contoh: HornetQ dan File :: Queue . Berikut adalah posting di SE yang mencantumkan beberapa opsi bagus lainnya: Antrian pesan dalam perl, php, python .

dabest1
sumber
Saya setuju dengan pendekatan ini - saya mengumpulkan ~ 1500 sisipan setiap 5 detik pada satu aplikasi dan itu adalah sub detik. mysql tampaknya memiliki beberapa mekanisme yang diimplementasikan secara internal yang membuat insert batch terjadi sangat cepat.
Don Wool