Data Anda buruk berkelompok .
InnoDB akan menyimpan baris dengan PK "tutup" yang berdekatan secara fisik. Karena tabel anak Anda menggunakan PK pengganti, barisnya akan disimpan secara acak. Ketika saatnya tiba untuk membuat perhitungan untuk baris yang diberikan dalam tabel "master", DBMS harus melompat ke mana-mana untuk mengumpulkan baris terkait dari tabel anak.
Alih-alih kunci pengganti, coba gunakan lebih banyak kunci "alami", dengan PK induk di ujung depan, mirip dengan ini:
score_adjustments:
entry_id: INT(11), FOREIGN KEY (entries.id)
created: DATETIME
amount: INT(4)
PRIMARY KEY (entry_id, created)
rating_adjustments:
entry_id: INT(11), FOREIGN KEY (entries.id)
rating_no: INT(11)
rating: DOUBLE
PRIMARY KEY (entry_id, rating_no)
CATATAN:Ini mengasumsikan created
resolusinya cukup baik dan rating_no
telah ditambahkan untuk memungkinkan beberapa peringkat per entry_id
. Ini hanyalah sebuah contoh - Anda dapat memvariasikan PK sesuai dengan kebutuhan Anda.
Ini akan "memaksa" baris milik entry_id
yang sama untuk disimpan secara fisik berdekatan, sehingga SUM atau AVG dapat dihitung hanya dengan pemindaian rentang pada kunci PK/pengelompokan dan dengan I/O yang sangat sedikit.
Atau (misalnya jika Anda menggunakan MyISAM yang tidak mendukung pengelompokan), penutup kueri dengan indeks sehingga tabel anak tidak disentuh sama sekali selama kueri.
Selain itu, Anda dapat mendenormalisasi desain Anda, dan menyimpan hasil saat ini di tabel induk:
- Simpan SUM(score_adjustments.amount) sebagai bidang fisik dan sesuaikan melalui pemicu setiap kali baris dimasukkan, diperbarui, atau dihapus dari
score_adjustments
. - Simpan SUM(rating_adjustments.rating) sebagai "S" dan COUNT(rating_adjustments.rating) sebagai "C". Saat baris ditambahkan ke
rating_adjustments
, tambahkan ke S dan kenaikan C. Hitung S/C saat run-time untuk mendapatkan rata-rata. Tangani pembaruan dan penghapusan dengan cara yang sama.