Vì bạn chưa đưa ra lược đồ cho results
, Tôi sẽ cho rằng nó giống cái này hoặc rất giống (có thể là cột bổ sung):
create table results (
id int primary key,
user int,
foreign key (user) references <some_other_table>(id),
keyword varchar(<30>)
);
Bước 1: tổng hợp theo keyword/user
như trong truy vấn mẫu của bạn, nhưng đối với tất cả các từ khóa:
create view user_keyword as (
select
keyword,
user,
count(*) as magnitude
from results
group by keyword, user
);
Bước 2: xếp hạng từng người dùng trong mỗi nhóm từ khóa (lưu ý việc sử dụng truy vấn con để xếp hạng các hàng):
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
);
Bước 3: chỉ chọn những hàng có xếp hạng nhỏ hơn một số:
select *
from keyword_user_ranked
where rank <= 3;
Ví dụ:
Dữ liệu cơ sở được sử dụng:
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 |
+----+------+---------+
Được nhóm theo từ khóa và người dùng:
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 |
+---------+------+-----------+
Người dùng được xếp hạng trong các từ khóa:
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 |
+---------+------+-----------+------+
Chỉ top 2 từ mỗi từ khóa:
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 |
+---------+------+-----------+------+
Lưu ý rằng khi có sự ràng buộc - hãy xem người dùng 2 và 4 cho từ khóa "mysql" trong ví dụ - tất cả các bên trong mối ràng buộc đều nhận được thứ hạng "cuối cùng", tức là nếu người thứ 2 và thứ 3 được ràng buộc, cả hai đều được chỉ định xếp hạng 3.
Hiệu suất:thêm chỉ mục vào từ khóa và các cột người dùng sẽ hữu ích. Tôi có một bảng đang được truy vấn theo cách tương tự với 4000 và 1300 giá trị khác biệt cho hai cột (trong bảng 600000 hàng). Bạn có thể thêm chỉ mục như sau:
alter table results add index keyword_user (keyword, user);
Trong trường hợp của tôi, thời gian truy vấn giảm từ khoảng 6 giây xuống còn khoảng 2 giây.