Karena Anda belum memberikan skema untuk results
, Saya akan menganggap ini atau sangat mirip (mungkin kolom tambahan):
create table results (
id int primary key,
user int,
foreign key (user) references <some_other_table>(id),
keyword varchar(<30>)
);
Langkah 1: agregat menurut keyword/user
seperti pada contoh kueri Anda, tetapi untuk semua kata kunci:
create view user_keyword as (
select
keyword,
user,
count(*) as magnitude
from results
group by keyword, user
);
Langkah 2: beri peringkat setiap pengguna dalam setiap grup kata kunci (perhatikan penggunaan subkueri untuk memberi peringkat pada baris):
create view keyword_user_ranked as (
select
keyword,
user,
magnitude,
(select count(*)
from user_keyword
where l.keyword = keyword and magnitude >= l.magnitude
) as rank
from
user_keyword l
);
Langkah 3: pilih hanya baris yang peringkatnya kurang dari beberapa angka:
select *
from keyword_user_ranked
where rank <= 3;
Contoh:
Data dasar yang digunakan:
mysql> select * from results;
+----+------+---------+
| id | user | keyword |
+----+------+---------+
| 1 | 1 | mysql |
| 2 | 1 | mysql |
| 3 | 2 | mysql |
| 4 | 1 | query |
| 5 | 2 | query |
| 6 | 2 | query |
| 7 | 2 | query |
| 8 | 1 | table |
| 9 | 2 | table |
| 10 | 1 | table |
| 11 | 3 | table |
| 12 | 3 | mysql |
| 13 | 3 | query |
| 14 | 2 | mysql |
| 15 | 1 | mysql |
| 16 | 1 | mysql |
| 17 | 3 | query |
| 18 | 4 | mysql |
| 19 | 4 | mysql |
| 20 | 5 | mysql |
+----+------+---------+
Dikelompokkan menurut kata kunci dan pengguna:
mysql> select * from user_keyword order by keyword, magnitude desc;
+---------+------+-----------+
| keyword | user | magnitude |
+---------+------+-----------+
| mysql | 1 | 4 |
| mysql | 2 | 2 |
| mysql | 4 | 2 |
| mysql | 3 | 1 |
| mysql | 5 | 1 |
| query | 2 | 3 |
| query | 3 | 2 |
| query | 1 | 1 |
| table | 1 | 2 |
| table | 2 | 1 |
| table | 3 | 1 |
+---------+------+-----------+
Peringkat pengguna dalam kata kunci:
mysql> select * from keyword_user_ranked order by keyword, rank asc;
+---------+------+-----------+------+
| keyword | user | magnitude | rank |
+---------+------+-----------+------+
| mysql | 1 | 4 | 1 |
| mysql | 2 | 2 | 3 |
| mysql | 4 | 2 | 3 |
| mysql | 3 | 1 | 5 |
| mysql | 5 | 1 | 5 |
| query | 2 | 3 | 1 |
| query | 3 | 2 | 2 |
| query | 1 | 1 | 3 |
| table | 1 | 2 | 1 |
| table | 3 | 1 | 3 |
| table | 2 | 1 | 3 |
+---------+------+-----------+------+
Hanya 2 teratas dari setiap kata kunci:
mysql> select * from keyword_user_ranked where rank <= 2 order by keyword, rank asc;
+---------+------+-----------+------+
| keyword | user | magnitude | rank |
+---------+------+-----------+------+
| mysql | 1 | 4 | 1 |
| query | 2 | 3 | 1 |
| query | 3 | 2 | 2 |
| table | 1 | 2 | 1 |
+---------+------+-----------+------+
Perhatikan bahwa ketika ada seri -- lihat pengguna 2 dan 4 untuk kata kunci "mysql" dalam contoh -- semua pihak dalam seri mendapatkan peringkat "terakhir", yaitu jika yang ke-2 dan ke-3 seri, keduanya diberi peringkat 3.
Kinerja:menambahkan indeks ke kata kunci dan kolom pengguna akan membantu. Saya memiliki tabel yang ditanyakan dengan cara yang sama dengan 4000 dan 1300 nilai berbeda untuk dua kolom (dalam tabel 600000-baris). Anda dapat menambahkan indeks seperti ini:
alter table results add index keyword_user (keyword, user);
Dalam kasus saya, waktu kueri turun dari sekitar 6 detik menjadi sekitar 2 detik.