+6

Tối ưu SQL - Subqueries Count Distinct (Phần 2)

Tiếp theo bài 1 về tối ưu performance.

Mình có các bảng như sau:

  1. dashboards(id, name)
CREATE TABLE `dashboards` (
  `id` int(11) NOT NULL,
  `name` int(11) NOT NULL,
  PRIMARY KEY (`id`)
)
  1. user_logs(id, user_id, dashboard_id)
CREATE TABLE `user_logs` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `dashboard_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

Yêu cầu bài toán đặt ra: Hiển thị ra tên dashboard và số lượng người truy cập vào dashboards dựa vào bảng logs theo thứ tự giảm dần. Ví dụ:

dashboard id dashboard name number of users
10 Dashboad 10 10000
2 Dashboad test 9999
1 Dashboad final 99

Theo như yêu cầu bài toán,

  • join bẳng dashboads với bảng user_logs,
  • sau đó group theo ul.dashboard_id
  • sort giảm dần như code bên dưới.
select d.id, d.name, count(distinct ul.dashboard_id) as count
from dashboards d
         join user_logs ul on d.id = ul.dashboard_id
group by ul.dashboard_id
order by count desc;

Dừng lại phân tích chút, bảng user_logs chứa rất nhiều data (10tr bản ghi, mỗi lần 1 user vào dashboard là lại được log lại). -> chưa tối ưu performance. ý tưởng tương tự như bài viết số 1 nghĩ cách giảm số lượng bản ghi trước khi join

Aggregate trước, join sau.

Nhận thấy bảng user_logs này, chỉ cần lấy thông tin dashboard_id và count(số lượng user đã truy cập), số lượng bản ghi tạo ra bằng số lượng dashboards

select dashboard_id, count(distinct user_id) as count
from user_logs group by dashboard_id;

sau đó join thì sẽ nhanh hơn rất nhiều. cuối cùng ta có.

select *
from dashboards d
         join
     (select dashboard_id, count(distinct user_id) as count
      from user_logs
      group by dashboard_id) temp_logs
     on d.id = temp_logs.dashboard_id
order by temp_logs.count desc;

Nếu vẫn muốn cải tiến perform, chúng ta làm như sau:

  1. Giảm số lượng bản ghi trong user_logs Ta nhận thấy trong bảng user_logs thì chỉ cần quan tâm đến cặp user_id, dashboard_id. Ví dụ 1 người vào xem dashboard 1000 lần thì chỉ cần 1 cặp duy nhất user_id, dashboard_id
select distinct user_id, dashboard_id
from user_logs;

Đoạn tiếp theo query tương tự ở bước trên cuối cùng ta có.

select *
from dashboards d
         join
     (select dashboard_id, count(distinct user_id) as count
      from (select distinct user_id, dashboard_id from user_logs) as user_dashboards
      group by dashboard_id) temp_logs
     on d.id = temp_logs.dashboard_id
order by temp_logs.count desc;

Nếu cần trao đổi, mọi người hãy bình luận bên dưới. Cảm ơn vì đã đọc bài của mình.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí