Process list di chapter sebelumnya menjawab pertanyaan siapa yang sedang melakukan apa pada satu momen. Namun administrator juga butuh jawaban atas pertanyaan kuantitatif: sudah berapa banyak query yang diproses server sejak menyala, berapa koneksi yang sedang terbuka, dan seberapa sering InnoDB berhasil membaca data langsung dari memori. Semua angka tersebut tinggal di server status variables yang kita baca dengan perintah SHOW STATUS. Chapter ini membedah dua scope status (session dan global), membuktikan perilaku counter di dalam satu sesi, lalu menutup dengan pola diagnosis cepat memakai angka-angka paling sering dipakai di lapangan.

Dua Scope Statistik: SESSION dan GLOBAL #

Mirip seperti system variable, status server juga punya scope. Sebagian besar status variable dihitung dalam dua salinan: salinan SESSION yang dimulai dari nol setiap kali koneksi dibuka, dan salinan GLOBAL yang terus terakumulasi sejak server dinyalakan. Perintah SHOW STATUS tanpa kata kunci scope menampilkan versi SESSION; untuk versi kumulatif server kita menuliskan SHOW GLOBAL STATUS secara eksplisit.

Sebelum mencoba, kita siapkan database latihan kecil terlebih dahulu supaya contoh berikutnya punya tabel sungguhan untuk diamati:

sql
DROP DATABASE IF EXISTS belajar_admin;
CREATE DATABASE belajar_admin;
USE belajar_admin;
CREATE TABLE kunjungan (id INT PRIMARY KEY, halaman VARCHAR(30));

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
Query OK, 0 rows affected (0.00 sec)

Satu hal penting tentang lingkungan uji: setiap blok contoh pada tutorial ini dijalankan dalam sesi klien yang baru dibuka, jadi counter sesi selalu kita amati dari kondisi awal yang sama. Angka pada server Anda tentu berbeda, namun pola naik-turunnya identik.

Counter Statement per Sesi: Com_select dan Com_insert #

Status variable berprefiks Com_ menghitung statement, bukan baris — satu INSERT yang menulis lima baris tetap dihitung sebagai satu. Kita amati counter Com_select dan Com_insert sebelum dan sesudah menjalankan query, semuanya dalam satu blok yang sama agar berbagi satu sesi:

sql
SHOW SESSION STATUS LIKE 'Com_select';
SHOW SESSION STATUS LIKE 'Com_insert';
INSERT INTO kunjungan VALUES (1, 'beranda'), (2, 'produk');
SELECT COUNT(*) AS jumlah_kunjungan FROM kunjungan;
SHOW SESSION STATUS LIKE 'Com_select';
SHOW SESSION STATUS LIKE 'Com_insert';

Output yang Dihasilkan:

text
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 1     |
+---------------+-------+
1 row in set (0.00 sec)

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_insert    | 0     |
+---------------+-------+
1 row in set (0.00 sec)

Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

+------------------+
| jumlah_kunjungan |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 2     |
+---------------+-------+
1 row in set (0.00 sec)

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_insert    | 1     |
+---------------+-------+
1 row in set (0.00 sec)

Mari kita bedah angka-angka di atas:

  1. Com_select awal bernilai 1, padahal kita belum menjalankan SELECT apa pun. Klien mysql diam-diam menjalankan SELECT @@version_comment LIMIT 1 saat menyapa server untuk mengisi banner versi — statement tersebut dihitung sebagai satu SELECT milik sesi kita.
  2. Com_insert bernilai 0 karena sesi ini memang belum pernah menulis apa pun.
  3. Setelah satu INSERT dan satu SELECT, Com_insert naik ke 1 meskipun baris yang ditulis ada dua, sementara Com_select naik ke 2. Counter menghitung statement, persis seperti uraian di awal bagian.

FLUSH STATUS: Mereset Counter Sesi #

Kadang kita ingin mengukur “berapa query yang terjadi karena beban kerja ini saja”. FLUSH STATUS me-nol-kan semua status variable ber-scope session untuk koneksi saat ini, sehingga pengukuran berikutnya mulai dari angka bersih:

sql
FLUSH STATUS;
SHOW SESSION STATUS LIKE 'Com_select';
SELECT COUNT(*) AS total_kunjungan FROM kunjungan;
SHOW SESSION STATUS LIKE 'Com_select';
SHOW GLOBAL STATUS LIKE 'Uptime_since_flush_status';

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 0     |
+---------------+-------+
1 row in set (0.00 sec)

+-----------------+
| total_kunjungan |
+-----------------+
|               2 |
+-----------------+
1 row in set (0.00 sec)

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 1     |
+---------------+-------+
1 row in set (0.00 sec)

+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| Uptime_since_flush_status | 0     |
+---------------------------+-------+
1 row in set (0.00 sec)

Setelah FLUSH STATUS, nilai Com_select turun ke 0 — pengaruh statement banner pembuka sesi pun terhapus. Satu SELECT kemudian menaikkannya menjadi 1, bukan 2 seperti sebelumnya. Perhatikan juga Uptime_since_flush_status: status variable global ini mencatat detik sejak FLUSH STATUS terakhir, dan nilainya ikut direset ke 0 oleh statement yang sama. Nilai Uptime_since_flush_status berguna sebagai jangkar waktu ketika kita mengukur laju beban (“dalam 5 menit terakhir”) tanpa perlu mencatat jam dinding.

Scope GLOBAL: Angka Kumulatif Server #

Sekarang sisi sebaliknya. SHOW GLOBAL STATUS membaca angka yang terkumpul dari seluruh koneksi sejak server menyala, sehingga nilainya bergantung pada usia dan riwayat beban server — dua hal yang berbeda-beda di setiap instalasi:

sql
-- @check
SHOW GLOBAL STATUS LIKE 'Com_select';
SHOW GLOBAL STATUS LIKE 'Questions';

Output yang Dihasilkan:

text
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 612   |
+---------------+-------+
1 row in set (0.00 sec)

+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Questions     | 24617   |
+---------------+---------+
1 row in set (0.00 sec)

Blok di atas ditandai @check karena angka seperti ini mustahil identik antar-server atau antar-waktu: Questions bertambah satu setiap kali server mengeksekusi satu statement dari klien mana pun. Justru sifat kumulatif itulah yang membuat angka global berguna — kita membandingkan pertumbuhannya (delta antar dua pembacaan), bukan nilai mutlaknya. Sebaliknya, beberapa status variable hanya punya scope global sehingga SHOW STATUS biasa pun menampilkan nilai globalnya:

sql
SHOW STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_connected';

Output yang Dihasilkan:

text
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 1     |
+-------------------+-------+
1 row in set (0.00 sec)

+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 1     |
+-------------------+-------+
1 row in set (0.00 sec)

Kedua perintah mengembalikan 1 karena Threads_connected memang hanya dihitung global. Nilai 1 di server latihan kita masuk akal: satu-satunya koneksi yang hidup adalah sesi kita sendiri. Thread internal seperti event_scheduler yang tampak di SHOW PROCESSLIST tidak dihitung sebagai koneksi klien. Di server produksi yang ramai, angka ini yang kita bandingkan dengan max_connections untuk mendeteksi koneksi yang menumpuk ke batas.

Terakhir, umur server sendiri tercatat di Uptime:

sql
-- @check
SHOW GLOBAL STATUS LIKE 'Uptime';

Output yang Dihasilkan:

text
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Uptime        | 7325  |
+---------------+-------+
1 row in set (0.00 sec)

Uptime berisi detik sejak proses mysqld terakhir kali dinyalakan. Membagi Questions dengan Uptime memberi gambaran kasar rata-rata statement per detik sepanjang umur server — angka pembuka percakapan yang cukup baik saat menerima serahan server baru.

Statistik Buffer Pool untuk Diagnosis Cepat #

Sebagian besar data InnoDB dilayani dari buffer pool di RAM; disk hanya tersentuh saat halaman data belum ada di memori. Dua status variable berikut memberi tahu seberapa sering server terpaksa turun ke disk — pola diagnosis paling sering dipakai saat menyelidiki performa:

sql
-- @check
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';

Output yang Dihasilkan:

text
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| Innodb_buffer_pool_reads  | 3521  |
+---------------------------+-------+
1 row in set (0.00 sec)

+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| Innodb_buffer_pool_read_requests | 189234    |
+----------------------------------+-----------+
1 row in set (0.00 sec)

Innodb_buffer_pool_read_requests menghitung permintaan baca yang dilayani langsung dari memori, sedangkan Innodb_buffer_pool_reads menghitung permintaan yang memaksa server membaca disk. Rasio hits dihitung dengan rumus (read_requests - reads) / read_requests — pada angka ilustratif di atas, (189234 - 3521) / 189234 menghasilkan sekitar 98,1% permintaan dilayani dari RAM. Server sehat umumnya berada di atas 99%; angka yang terus menurun menjadi sinyal bahwa innodb_buffer_pool_size perlu ditambah atau beban query memindai data melebihi kapasitas memori.

Tabel berikut merangkum status variable yang paling sering menjadi titik awal diagnosis:

Status variablePertanyaan yang dijawab
Threads_connected vs max_connectionsapakah koneksi menumpuk mendekati batas?
Questions dan Uptimeberapa rata-rata beban statement per detik?
Com_select, Com_insert, Com_update, Com_deleteprofil beban: dominan baca atau tulis?
Innodb_buffer_pool_reads vs read_requestsapakah cache memori memadai?
Slow_queriessudah berapa query melewati ambang slow log?

Baris terakhir menjadi jembatan alami: counter Slow_queries hanya memberi tahu berapa banyak query yang lambat, bukan query mana. Untuk mengetahui query mana yang lambat, MySQL menyimpan rekamannya di slow query log.

Referensi #

Kita kini bisa membaca detak jantung server lewat angka-angka statusnya. Angka-angka itu sendiri sebenarnya berasal dari struktur data internal yang tersebar di beberapa database sistem — mysql, information_schema, dan kawan-kawannya. Chapter berikutnya membuka isi keempat database sistem tersebut dan aturan main yang menjaganya.