Apa cara paling efisien untuk mengelompokkan permintaan UPDATE di MySQL?

10

Saya sedang menulis sebuah aplikasi yang perlu untuk menghapus sejumlah besar pembaruan ke database untuk jangka waktu yang lama, dan saya terjebak pada cara mengoptimalkan kueri. Saat ini saya menggunakan INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, yang berfungsi untuk mengelompokkan semua nilai menjadi satu permintaan, tetapi dieksekusi dengan sangat lambat pada tabel besar. Saya tidak pernah benar-benar perlu memasukkan baris.

Pendekatan lain yang saya lihat adalah memperbarui menggunakan SET value = CASE WHEN...(yang akan sulit untuk menghasilkan karena cara saya membangun permintaan, dan saya tidak yakin tentang kinerja CASEuntuk ratusan / ribuan kunci), dan hanya beberapa digabungkan pembaruan. Apakah salah satu dari ini lebih cepat daripada metode saya saat ini?

Ini membuat saya bingung, sejauh yang saya tahu, tidak ada cara idiomatis, efisien untuk melakukan ini di MySQL. Jika benar-benar tidak ada cara yang lebih cepat daripada itu ON DUPLICATE KEY, apakah itu layak untuk beralih ke PostgreSQL dan menggunakan UPDATE FROMsintaksnya?

Saran lain juga sangat dihargai!

Sunting: inilah salah satu tabel yang sering diperbarui. Saya telah menghapus nama kolom karena tidak relevan.

CREATE TABLE IF NOT EXISTS `table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `a` bigint(20) unsigned NOT NULL DEFAULT '0',
  `b` bigint(20) unsigned NOT NULL DEFAULT '0',
  `c` enum('0','1','2') NOT NULL DEFAULT '0',
  `d` char(32) NOT NULL,
  -- trimmed --
  PRIMARY KEY (`id`),
  KEY `a` (`a`),
  KEY `b` (`b`),
  KEY `c` (`c`),
  KEY `d` (`d`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
jli
sumber
Ini pada mesin pengujian dan bukan pada produksi sehingga InnoDB tidak sepenuhnya disetel dengan benar. Saya tidak sepenuhnya yakin tentang bagaimana INSERT FROM beroperasi, tetapi apa yang Anda katakan sepertinya benar. Memperbarui pertanyaan dengan info yang Anda minta.
JLI

Jawaban:

14

Karena Anda menggunakan InnoDBtabel, pengoptimalan yang paling jelas adalah mengelompokkan beberapa UPDATEke dalam suatu transaksi.

Dengan InnoDB, sebagai mesin transaksional, Anda membayar tidak hanya untuk UPDATEdirinya sendiri, tetapi juga untuk semua overhead transaksional: mengelola buffer transaksi, log transaksi, menyiram log ke disk.

Jika Anda secara logis nyaman dengan ide tersebut, cobalah dan kelompokkan 100-1000 UPDATEs sekaligus, setiap kali dibungkus seperti ini:

START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;

Kerugian yang mungkin terjadi:

  • Satu kesalahan akan meruntuhkan seluruh transaksi (tetapi akan mudah diperbaiki dalam kode)
  • Anda mungkin menunggu untuk waktu yang lama untuk mengakumulasi 1000 UPDATEdetik Anda, jadi Anda mungkin juga ingin memiliki batas waktu
  • Lebih rumit pada kode aplikasi Anda.
Shlomi Noach
sumber