Da du ikke har givet skemaet for results
, jeg antager, at det er denne eller meget lignende (måske ekstra kolonner):
create table results (
id int primary key,
user int,
foreign key (user) references <some_other_table>(id),
keyword varchar(<30>)
);
Trin 1: samle efter keyword/user
som i din eksempelforespørgsel, men for alle søgeord:
create view user_keyword as (
select
keyword,
user,
count(*) as magnitude
from results
group by keyword, user
);
Trin 2: ranger hver bruger inden for hver søgeordsgruppe (bemærk brugen af underforespørgslen til at rangere rækkerne):
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
);
Trin 3: vælg kun de rækker, hvor rangeringen er mindre end et tal:
select *
from keyword_user_ranked
where rank <= 3;
Eksempel:
Anvendte basisdata:
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 |
+----+------+---------+
Grupperet efter søgeord og bruger:
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 |
+---------+------+-----------+
Brugere rangeret inden for søgeord:
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 |
+---------+------+-----------+------+
Kun top 2 fra hvert søgeord:
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 |
+---------+------+-----------+------+
Bemærk, at når der er uafgjort -- se brugere 2 og 4 for søgeordet "mysql" i eksemplerne -- får alle parter i uafgjort den "sidste" rang, dvs. hvis 2. og 3. er lige, tildeles begge rang 3.
Ydeevne:Tilføjelse af et indeks til søgeords- og brugerkolonnerne vil hjælpe. Jeg har en tabel, der forespørges på en lignende måde med 4000 og 1300 forskellige værdier for de to kolonner (i en tabel med 600.000 rækker). Du kan tilføje indekset sådan her:
alter table results add index keyword_user (keyword, user);
I mit tilfælde faldt forespørgselstiden fra omkring 6 sekunder til omkring 2 sekunder.