Saya sedang mengerjakan skema untuk sistem analitik yang melacak waktu penggunaan, dan ada kebutuhan untuk melihat total waktu penggunaan dalam rentang tanggal tertentu.
Untuk memberikan contoh sederhana, jenis kueri ini akan sering dijalankan:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Kueri ini biasanya memakan waktu sekitar 7 detik pada tabel yang padat. Ini memiliki ~ 35 juta baris, MyISAM di MySQL berjalan di Amazon RDS (db.m3.xlarge).
Menyingkirkan klausa WHERE membuat kueri hanya membutuhkan waktu 4 detik, dan menambahkan klausa kedua (time_off> XXX) menambahkan 1,5 detik tambahan, menjadikan waktu kueri menjadi 8,5 detik.
Karena saya tahu jenis pertanyaan ini akan umum dilakukan, saya ingin mengoptimalkan beberapa hal sehingga lebih cepat, idealnya di bawah 5 detik.
Saya mulai dengan menambahkan indeks pada time_on, dan meskipun secara drastis mempercepat permintaan WHERE "=", itu tidak berpengaruh pada kueri ">". Apakah ada cara untuk membuat indeks yang akan mempercepat permintaan WHERE ">" atau "<"?
Atau jika ada saran lain tentang kinerja jenis permintaan ini, beri tahu saya.
Catatan: Saya menggunakan bidang "diff_ms" sebagai langkah denormalisasi (sama dengan time_off - time_on) yang meningkatkan kinerja agregasi sekitar 30% -40%.
Saya membuat indeks dengan perintah ini:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
Menjalankan "jelaskan" pada permintaan asli (dengan "time_on>") mengatakan time_on adalah "mungkin_kunci" dan select_type adalah "SIMPLE". Kolom "ekstra" mengatakan "Menggunakan tempat", dan "ketik" adalah "SEMUA". Setelah indeks ditambahkan, tabel mengatakan "time_on" adalah tipe kunci "MUL", yang tampaknya benar karena waktu yang sama dapat hadir dua kali.
Berikut adalah skema tabel:
CREATE TABLE `writetest_table` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sessionID` int(11) DEFAULT NULL,
`time_on` timestamp NULL DEFAULT NULL,
`time_off` timestamp NULL DEFAULT NULL,
`diff_ms` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `time_on` (`time_on`)
) ENGINE=MyISAM AUTO_INCREMENT=50410902 DEFAULT CHARSET=latin1;
PEMBARUAN: Saya membuat indeks berikut berdasarkan respons ypercube, tetapi ini meningkatkan waktu kueri untuk kueri pertama menjadi sekitar 17 detik!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
UPDATE 2: MENJELASKAN output
mysql> explain select sum(diff_ms) from writetest_table where time_on > '2015-07-13 15:11:56';
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| 1 | SIMPLE | writetest_table_old | index | time_on__diff_ms__ix | time_on__diff_ms__ix | 10 | NULL | 35831102 | Using where; Using index |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
1 row in set (0.00 sec)
Pembaruan 3: hasil dari permintaan yang diminta
mysql> SELECT time_on FROM writetest_table ORDER BY time_on LIMIT 1;
+---------------------+
| time_on |
+---------------------+
| 2015-07-13 15:11:56 |
+---------------------+
1 row in set (0.01 sec)
SELECT COUNT(*), COUNT(diff_ms) FROM writetest_table;
writetest_table_old
" sementara permintaan memiliki from writetest_table
. Apakah itu salah ketik atau Anda menjalankan kueri di tabel yang berbeda?
time_on
dandiff_ms
)? Apa yang terjadi jika Anda menambahkan dalam kueriWHERE ... AND diff_ms IS NOT NULL
?