Masalah:
Kami memiliki situs sosial di mana anggota dapat menilai satu sama lain untuk kompatibilitas atau pencocokan. user_match_ratings
Tabel ini berisi lebih dari 220 juta baris (9 pertunjukan data atau hampir 20 pertunjukan dalam indeks). Kueri terhadap tabel ini secara rutin muncul di slow.log (ambang> 2 detik) dan merupakan kueri lambat yang paling sering dicatat dalam sistem:
Query_time: 3 Lock_time: 0 Rows_sent: 3 Rows_examined: 1051
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 395357 group by rating;"
Query_time: 4 Lock_time: 0 Rows_sent: 3 Rows_examined: 1294
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 4182969 group by rating;"
Query_time: 3 Lock_time: 0 Rows_sent: 3 Rows_examined: 446
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 630148 group by rating;"
Query_time: 5 Lock_time: 0 Rows_sent: 3 Rows_examined: 3788
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1835698 group by rating;"
Query_time: 17 Lock_time: 0 Rows_sent: 3 Rows_examined: 4311
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1269322 group by rating;"
Versi MySQL:
- versi protokol: 10
- versi: 5.0.77-log
- versi bdb: Perangkat Lunak Sleepycat: Berkeley DB 4.1.24: (29 Januari 2009)
- mesin kompilasi versi: x86_64 version_compile_os: redhat-linux-gnu
Info tabel:
SHOW COLUMNS FROM user_match_ratings;
Memberi:
╔═══════════════╦════════════╦════╦═════╦════════╦════════════════╗
║ id ║ int(11) ║ NO ║ PRI ║ NULL ║ auto_increment ║
║ rater_user_id ║ int(11) ║ NO ║ MUL ║ NULL ║ ║
║ rated_user_id ║ int(11) ║ NO ║ MUL ║ NULL ║ ║
║ rating ║ varchar(1) ║ NO ║ ║ NULL ║ ║
║ created_at ║ datetime ║ NO ║ ║ NULL ║ ║
╚═══════════════╩════════════╩════╩═════╩════════╩════════════════╝
Permintaan sampel:
select * from mutual_match_ratings where id=221673540;
memberi:
╔═══════════╦═══════════════╦═══════════════╦════════╦══════════════════════╗
║ id ║ rater_user_id ║ rated_user_id ║ rating ║ created_at ║
╠═══════════╬═══════════════╬═══════════════╬════════╬══════════════════════╣
║ 221673540 ║ 5699713 ║ 3890950 ║ N ║ 2013-04-09 13:00:38 ║
╚═══════════╩═══════════════╩═══════════════╩════════╩══════════════════════╝
Indeks
Tabel ini memiliki 3 indeks yang diatur:
- indeks tunggal aktif
rated_user_id
- indeks komposit pada
rater_user_id
dancreated_at
- indeks komposit pada
rated_user_id
danrater_user_id
tampilkan indeks dari user_match_ratings;
memberi:
╔════════════════════╦════════════╦═══════════════════════════╦══════════════╦═══════════════╦═══════════╦═════════════╦══════════╦════════╦═════════════════════════╦════════════╦══════════════════╗
║ Table ║ Non_unique ║ Key_name ║ Seq_in_index ║ Column_name ║ Collation ║ Cardinality ║ Sub_part ║ Packed ║ Null ║ Index_type ║ Comment ║
╠════════════════════╬════════════╬═══════════════════════════╬══════════════╬═══════════════╬═══════════╬═════════════╬══════════╬════════╬═════════════════════════╬════════════╬══════════════════╣
║ user_match_ratings ║ 0 ║ PRIMARY ║ 1 ║ id ║ A ║ 220781193 ║ NULL ║ NULL ║ BTREE ║ ║ ║
║ user_match_ratings ║ 1 ║ user_match_ratings_index1 ║ 1 ║ rater_user_id ║ A ║ 11039059 ║ NULL ║ NULL ║ BTREE ║ ║ ║
║ user_match_ratings ║ 1 ║ user_match_ratings_index1 ║ 2 ║ created_at ║ A ║ 220781193 ║ NULL ║ NULL ║ BTREE ║ ║ ║
║ user_match_ratings ║ 1 ║ user_match_ratings_index2 ║ 1 ║ rated_user_id ║ A ║ 4014203 ║ NULL ║ NULL ║ BTREE ║ ║ ║
║ user_match_ratings ║ 1 ║ user_match_ratings_index2 ║ 2 ║ rater_user_id ║ A ║ 220781193 ║ NULL ║ NULL ║ BTREE ║ ║ ║
║ user_match_ratings ║ 1 ║ user_match_ratings_index3 ║ 1 ║ rated_user_id ║ A ║ 2480687 ║ NULL ║ NULL ║ BTREE ║ ║ ║
╚════════════════════╩════════════╩═══════════════════════════╩══════════════╩═══════════════╩═══════════╩═════════════╩══════════╩════════╩═════════════════════════╩════════════╩══════════════════╝
Bahkan dengan indeks permintaan ini lambat.
Pertanyaan saya:
Apakah memisahkan tabel / data ini ke database lain di server yang memiliki ram cukup untuk menyimpan data ini dalam memori akankah ini mempercepat pertanyaan ini? Apakah ada hal lain yang mengatur tabel / indeks yang dapat kita tingkatkan untuk membuat kueri ini lebih cepat?
Saat ini kami memiliki memori 16GB; namun kami sedang mencari cara meningkatkan mesin yang ada ke 32GB atau menambahkan mesin baru dengan setidaknya sebanyak itu, mungkin solid state drive juga.
sumber
SELECT QUERY
. Tolong sarankan? PS Pertanyaan Anda memaksa saya untuk bergabung dengan komunitas ini (y);)Jawaban:
Pikiran tentang masalah ini, dilemparkan secara acak:
Indeks jelas untuk query ini adalah:
(rated_user_id, rating)
. Kueri yang mendapatkan data hanya untuk satu dari satu juta pengguna dan membutuhkan 17 detik adalah melakukan sesuatu yang salah: membaca dari(rated_user_id, rater_user_id)
indeks dan kemudian membaca dari tabel nilai (ratusan hingga ribuan) untukrating
kolom, karenarating
tidak ada dalam indeks apa pun. Jadi, kueri harus membaca banyak baris tabel yang terletak di berbagai lokasi disk.Sebelum mulai menambahkan banyak indeks dalam tabel, cobalah untuk menganalisis kinerja seluruh database, seluruh rangkaian pertanyaan yang lambat, periksa kembali pilihan dari tipe data, mesin yang Anda gunakan dan pengaturan konfigurasi.
Pertimbangkan untuk pindah ke versi MySQL yang lebih baru, 5.1, 5.5 atau bahkan 5.6 (juga: versi Percona dan MariaDB.) Beberapa manfaat sebagai bug telah diperbaiki, pengoptimal ditingkatkan dan Anda dapat mengatur ambang rendah untuk kueri lambat menjadi kurang dari 1 detik (seperti 10 milidetik). Ini akan memberi Anda info yang jauh lebih baik tentang permintaan lambat.
Pilihan untuk tipe data
rating
aneh.VARCHAR(1)
? Mengapa tidakCHAR(1)
? Mengapa tidakTINYINT
? Ini akan menghemat ruang, baik timah tabel dan indeks yang (akan) menyertakan kolom itu. Kolom varchar (1) membutuhkan satu byte lebih dari char (1) dan jika mereka utf8, kolom char (var) akan membutuhkan 3 (atau 4) byte, bukan 1 (tinyint).sumber
Saya menangani tabel untuk Pemerintah Jerman dengan kadang-kadang 60 juta catatan.
Kami punya banyak tabel ini.
Dan kami perlu tahu berkali-kali jumlah baris dari sebuah tabel.
Setelah berbicara dengan programmer Oracle dan Microsoft kami tidak begitu bahagia ...
Jadi kami, kelompok pemrogram basis data, memutuskan bahwa dalam setiap tabel ada catatan satu selalu catatan di mana jumlah total catatan disimpan. Kami memperbarui nomor ini, tergantung pada baris INSERT atau DELETE.
Kami mencoba semua cara lain. Ini adalah cara tercepat.
Kami menggunakan cara ini sekarang sejak tahun 1998 dan tidak pernah salah jumlah baris, di semua tabel multi-juta catatan kami.
sumber
count(*)
ada beberapa peningkatan.Saya akan mencoba mempartisi pada jenis peringkat, seperti:
mutual_match_ratings_N, mutual_match_ratings_S, dll.
Anda harus melakukan kueri untuk setiap jenis, tetapi mungkin itu lebih cepat daripada cara lainnya. Cobalah.
Ini mengasumsikan Anda memiliki sejumlah tipe peringkat tetap, dan bahwa Anda tidak memerlukan tabel ini untuk kueri lain yang akan lebih buruk dengan struktur baru ini.
Jika itu masalahnya, Anda harus mencari pendekatan lain, atau mempertahankan dua salinan tabel (tabel awal Anda, dan yang dipartisi) jika itu terjangkau dalam hal ruang dan rawatan (atau logika aplikasi).
sumber