Cache permintaan adalah fitur yang sangat bagus, tetapi jangan tergoda untuk terlalu memperhatikannya dan jangan tergoda untuk membuatnya terlalu besar. Memahami beberapa internal mungkin akan membantu dalam hal itu.
Cache permintaan dimulai sebagai satu potongan besar dari memori yang tersedia. Lalu "balok" diukir dari balok besar ini:
- setiap permintaan yang di-cache mengambil blok
- resultset pendampingnya mengambil blok
- setiap tabel direferensikan oleh kueri yang di-cache (tidak peduli berapa banyak kueri yang mereferensikan tabel itu dalam cache) juga membutuhkan satu blok, satu per tabel.
Ukuran blok adalah dinamis, tetapi server mengalokasikan minimum query_cache_min_res_unit
byte per blok, dengan standar khas 4096 byte.
Setiap permintaan waktu, hasil yang menyertainya, dan referensi tabel dihapus dari cache, baik dengan menjadi tidak valid oleh perubahan tabel yang mendasarinya atau dengan pemangkasan untuk memberikan ruang bagi permintaan yang lebih baru, ini membuat lubang baru ukuran seberapa besar blok itu, dan jumlah "blok bebas" biasanya meningkat ... walaupun jika dua atau lebih blok yang berdekatan dilepaskan, jumlah "blok bebas" hanya meningkat sebesar 1, dan "blok bebas" tidak akan bertambah sama sekali jika blok yang dibebaskan bersebelahan dengan blok yang sudah bebas - ukuran blok gratis itu menjadi lebih besar. Setiap blok memori bebas yang terbuka di cache kueri dihitung sebagai 1 blok gratis.
Tentu saja, blok gratis yang lebih kecil daripada query_cache_min_res_unit
tidak akan digunakan sama sekali.
Jadi, fragmen cache kueri. Jika server ingin men-cache permintaan baru dan tidak ada blok gratis dengan ukuran yang cukup dapat diatur (deskripsi itu tampak sederhana, karena algoritma yang mendasarinya rumit), sesuatu yang lain harus dipangkas ... itu Anda Qcache_lowmem_prunes
. Ada algoritma "LRU) yang paling baru-baru ini digunakan yang memutuskan apa yang akan dipangkas.
Akan masuk akal untuk bertanya mengapa server tidak mendefrag memori ... tetapi itu tidak masuk akal. Cache permintaan membantu ketika bisa tetapi itu sama sekali tidak strategis. Anda tidak ingin menginvestasikan waktu pemrosesan (terutama waktu yang dihabiskan dalam kunci global) dengan tugas pemeliharaan yang tidak perlu.
Akan menjadi kontra-produktif bagi server untuk menghabiskan waktu menata ulang - defragmenting - memori dalam cache kueri, karena hasil cache terus-menerus berubah dan seluruh titik cache adalah untuk meningkatkan kinerja.
Kunci global adalah alasan yang sangat bagus mengapa Anda tidak ingin menggunakan cache permintaan yang terlalu besar ... server akan menghabiskan terlalu banyak waktu di sana karena pertanyaan menunggu giliran mereka untuk melihat apakah mereka di-cache dan kinerja Anda akan menderita .
Tetapi pada qcache_free_blocks
dasarnya merupakan indikator fragmentasi ruang bebas. Itu sekarang banyak blok memori yang tidak berdampingan yang ada di cache kueri. Agar kueri baru dimasukkan ke dalam cache, harus ada ruang kosong yang cukup besar untuk memuat kueri, hasilnya, dan (kadang-kadang) referensi tabelnya. Jika tidak ada, maka sesuatu yang lain harus pergi ... yang Anda lihat. Perhatikan, sekali lagi, bahwa ruang yang tersedia tidak selalu harus bersebelahan (dari apa yang dapat saya katakan dengan membaca kode sumber), tetapi tidak setiap lubang akan diisi ketika ada fragmentasi.
Namun fragmentasi cenderung meningkat seiring berjalannya waktu, karena beban kerja yang diberikan, karena tidak ada yang biasanya tetap dalam cache kueri selama yang Anda harapkan.
Ini karena, dalam beberapa hal, cache permintaan brilian dalam kesederhanaannya.
Kapan saja data dalam tabel yang direferensikan oleh perubahan cache di-cache, semua kueri yang terkait dengan tabel tersebut dihapus dari cache - bahkan jika perubahan tidak berdampak pada hasil yang di-cache. Ini bahkan berlaku jika tabel berubah, tetapi tidak berubah, seperti dalam kasus transaksi InnoDB yang dibatalkan. Entri cache permintaan referensi tabel itu sudah dibersihkan.
Juga, cache permintaan diperiksa untuk setiap permintaan yang masuk sebelum server benar-benar mem-parsing permintaan. Satu-satunya hal yang akan cocok adalah kueri lain yang persis sama, byte-for-byte. SELECT * FROM my_table
dan select * from my_table
tidak identik byte-untuk-byte, sehingga cache kueri tidak menyadari bahwa mereka adalah query yang sama.
FLUSH QUERY CACHE
tidak mengosongkan cache kueri. Ini mendefrag cache permintaan, yang mengapa Qcache_free_blocks
menjadi "1." Semua ruang kosong dikonsolidasikan.
RESET QUERY CACHE
sebenarnya flushes (menghapus semua konten) cache permintaan.
FLUSH STATUS
membersihkan penghitung, tetapi ini bukan sesuatu yang ingin Anda lakukan secara rutin karena ini menghilangkan sebagian besar variabel status di SHOW STATUS
.
Berikut ini beberapa demonstrasi cepat.
Baseline:
mysql> show status like '%qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
Jalankan kueri ...
mysql> select * from junk where id = 2;
Total blok meningkat sebesar 3, menyisipkan 1 dan kueri dalam cache adalah 1.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67089584 |
| Qcache_inserts | 1 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+----------+
Jalankan kueri yang sama, tetapi dengan kapitalisasi berbeda ...
mysql> SELECT * FROM junk where id = 2;
Permintaan ini di-cache secara terpisah. Total blok hanya bertambah 2 karena kami sudah memiliki blok yang dialokasikan untuk tabel.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67088560 |
| Qcache_inserts | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+----------+
Sekarang, kita mengubah baris berbeda di tabel.
mysql> update junk set things = 'items' where id = 1;
Baik kueri dan referensi tabel tidak valid dari cache, meninggalkan kami dengan 1 blok bebas yang berdekatan, semua memori cache dibebaskan, dan semua ruang kosong dikonsolidasikan dalam satu blok.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
MySQL tidak akan menyimpan kueri dalam cache yang tidak deterministik - seperti SELECT NOW();
atau kueri apa pun yang Anda katakan secara khusus untuk tidak cache. SELECT SQL_NO_CACHE ...
adalah arahan untuk memberi tahu server untuk tidak menyimpan hasil dalam cache. Ini berguna untuk membuat tolok ukur waktu eksekusi sebenarnya dari sebuah kueri ketika cache memberi Anda respons yang sangat cepat pada eksekusi berikutnya.