Phân tích funnel
Bạn sẽ học được
- Định nghĩa funnel và các bước đo.
- Viết SQL tính số người ở từng bước.
- Phân biệt tỷ lệ theo bước và tỷ lệ trên tổng.
- Xác định bước rơi lớn nhất và cách điều tra.
- Xử lý các câu hỏi tiếp theo về cửa sổ thời gian và thứ tự sự kiện.
Khái niệm cốt lõi
Funnel mô tả một chuỗi hành vi mà người dùng phải đi qua, và số người còn lại ở mỗi bước. Đây là dạng câu hỏi phổ biến vì nó buộc bạn vừa viết SQL vừa đọc được ý nghĩa kinh doanh.
Ví dụ một sàn thương mại điện tử:
| Bước | Số người |
|---|---|
| Xem sản phẩm | 200.000 |
| Thêm vào giỏ | 60.000 |
| Bắt đầu thanh toán | 18.000 |
| Hoàn tất thanh toán | 13.500 |
Hai loại tỷ lệ:
- Tỷ lệ theo bước: bước sau chia bước trước. 60.000/200.000 = 30%; 18.000/60.000 = 30%; 13.500/18.000 = 75%.
- Tỷ lệ trên tổng: chia cho bước đầu. 13.500/200.000 = 6,75%.
Cả hai đều cần nói. Tỷ lệ theo bước cho biết chỗ nào gãy; tỷ lệ trên tổng cho biết hiệu quả toàn phễu.
Điều cần làm rõ trước khi viết SQL
- Một phiên hay nhiều phiên? Người dùng xem hôm nay, mua ngày mai có tính là một funnel không?
- Thứ tự có bắt buộc? Phải xem → thêm giỏ → thanh toán đúng thứ tự, hay chỉ cần có đủ ba sự kiện?
- Cửa sổ thời gian? 1 ngày, 7 ngày, 30 ngày?
- Đếm người hay đếm lượt? Một người xem 5 sản phẩm là 1 hay 5?
- Sự kiện trùng lặp? Bấm "thêm vào giỏ" ba lần chỉ tính một.
Mặc định hợp lý trong phỏng vấn: một người, một cửa sổ 7 ngày, thứ tự có, đếm người.
Ví dụ chạy được
Bảng events(user_id, event_name, event_time).
Cách 1 — đếm người ở từng bước, có kiểm tra thứ tự.
with base as (
select user_id, event_name, event_time
from events
where event_time >= '2026-03-01'
and event_time < '2026-03-08'
),
step1 as (
select distinct user_id from base
where event_name = 'product_view'
),
step2 as (
select distinct b.user_id
from base b
join step1 s using (user_id)
where b.event_name = 'add_to_cart'
and b.event_time > (
select min(e.event_time) from base e
where e.user_id = b.user_id and e.event_name = 'product_view'
)
),
step3 as (
select distinct b.user_id
from base b
join step2 s using (user_id)
where b.event_name = 'checkout_start'
and b.event_time > (
select min(e.event_time) from base e
where e.user_id = b.user_id and e.event_name = 'add_to_cart'
)
),
step4 as (
select distinct b.user_id
from base b
join step3 s using (user_id)
where b.event_name = 'purchase'
and b.event_time > (
select min(e.event_time) from base e
where e.user_id = b.user_id and e.event_name = 'checkout_start'
)
)
select
(select count(*) from step1) as buoc_1,
(select count(*) from step2) as buoc_2,
(select count(*) from step3) as buoc_3,
(select count(*) from step4) as buoc_4;Cách 2 — gọn hơn bằng min theo từng sự kiện, phù hợp khi chỉ cần số liệu tổng.
with t as (
select
user_id,
min(event_time) filter (where event_name = 'product_view') as t1,
min(event_time) filter (where event_name = 'add_to_cart') as t2,
min(event_time) filter (where event_name = 'checkout_start') as t3,
min(event_time) filter (where event_name = 'purchase') as t4
from events
where event_time >= '2026-03-01' and event_time < '2026-03-08'
group by user_id
)
select
count(*) filter (where t1 is not null) as buoc_1,
count(*) filter (where t1 is not null and t2 > t1) as buoc_2,
count(*) filter (where t1 is not null and t2 > t1 and t3 > t2) as buoc_3,
count(*) filter (where t1 is not null and t2 > t1 and t3 > t2 and t4 > t3) as buoc_4
from t;Cách 2 dễ đọc và đủ nhanh cho hầu hết dữ liệu vừa. Cách 1 dễ mở rộng khi mỗi bước có điều kiện riêng.
Tính tỷ lệ:
select
buoc_1,
buoc_2,
round(100.0 * buoc_2 / buoc_1, 1) as ty_le_1_2,
round(100.0 * buoc_3 / buoc_2, 1) as ty_le_2_3,
round(100.0 * buoc_4 / buoc_3, 1) as ty_le_3_4,
round(100.0 * buoc_4 / buoc_1, 2) as ty_le_tong
from funnel;Với số liệu trên:
30,0% | 30,0% | 75,0% | 6,75%Đọc kết quả
Bước rơi lớn nhất là bước 1 → 2: mất 70% người dùng. Nhưng "lớn nhất" chưa chắc là "đáng sửa nhất". Cần so với chuẩn ngành và với lịch sử:
- Nếu tỷ lệ này luôn là 30% trong 12 tháng, nó là đặc điểm của sản phẩm, không phải sự cố.
- Nếu tháng trước là 45% và nay còn 30%, có gì đó vừa thay đổi.
Câu hỏi tiếp theo nên hỏi:
| Hiện tượng | Giả thuyết |
|---|---|
| Bước 1→2 giảm | Trang sản phẩm chậm, hết hàng, giá tăng |
| Bước 2→3 giảm | Phí vận chuyển hiện ra muộn, yêu cầu đăng nhập |
| Bước 3→4 giảm | Cổng thanh toán lỗi, thiếu phương thức |
| Tất cả cùng giảm | Lưu lượng kém chất lượng, tracking sai |
Với bước 1→2, việc đầu tiên là kiểm tra tracking sự kiện add_to_cart có còn ghi đúng không. Sau đó mới tới A/B test thay đổi giao diện.
Bẫy thường gặp
Không kiểm tra thứ tự. Nếu chỉ đếm người có cả ba sự kiện mà không so thời gian, người thêm giỏ trước khi xem sản phẩm vẫn được tính. Con số sẽ cao hơn thực tế.
Cửa sổ quá ngắn. Người dùng xem hôm nay, mua ngày mai bị loại nếu cửa sổ là 1 ngày. Chọn cửa sổ theo chu kỳ mua thực tế.
Đếm sự kiện thay vì người. count(*) cho ra số lượt; funnel cần số người.
Không loại sự kiện trùng. Một người bấm thêm giỏ ba lần vẫn là một người ở bước 2. distinct user_id xử lý việc này.
So sánh funnel giữa các nhóm có cửa sổ khác nhau. Nhóm A đo 7 ngày, nhóm B đo 30 ngày — không so sánh được.
Bỏ qua người dùng đã mua trước đó. Với sản phẩm mua lặp lại, cần tách người mới và người cũ, nếu không funnel bị pha loãng.
Trình bày trong phỏng vấn
- Làm rõ: đếm người, cửa sổ 7 ngày, thứ tự bắt buộc.
- Nêu công thức: tỷ lệ bước = bước sau / bước trước; tổng = cuối / đầu.
- Viết SQL theo một trong hai cách trên.
- Đọc kết quả: chỉ ra bước rơi lớn nhất, so với lịch sử.
- Đề xuất: kiểm tra tracking trước, rồi mới thử nghiệm thay đổi.
Nếu được hỏi "bạn sẽ cải thiện funnel này thế nào", trả lời bằng một giả thuyết cụ thể và cách đo, không phải danh sách ý tưởng chung chung.
Thực hành
- Viết funnel ba bước cho bảng
events. - Tính cả tỷ lệ theo bước và tỷ lệ tổng.
- Thêm điều kiện thứ tự thời gian và so sánh kết quả khi bỏ điều kiện đó.
- Đổi cửa sổ từ 1 ngày sang 7 ngày, ghi lại chênh lệch.
- Viết ba giả thuyết cho bước rơi lớn nhất và cách kiểm tra từng giả thuyết.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| Số bước sau lớn hơn bước trước | Không kiểm tra thứ tự | So event_time giữa các bước |
| Funnel cao bất thường | Đếm sự kiện, không đếm người | count(distinct user_id) |
| Số liệu thay đổi mỗi lần chạy | Dữ liệu đến muộn | Chốt ngày, chạy lại sau 24 giờ |
| Không so sánh được giữa các nhóm | Cửa sổ khác nhau | Chuẩn hoá cửa sổ |
| Bỏ sót người mua muộn | Cửa sổ quá ngắn | Chọn theo chu kỳ mua |
Tóm tắt
- Funnel cần chốt: đếm người, cửa sổ thời gian, thứ tự sự kiện.
- Tỷ lệ theo bước chỉ ra chỗ gãy; tỷ lệ tổng cho biết hiệu quả toàn phễu.
- Kiểm tra tracking trước khi kết luận về hành vi người dùng.
- Bước rơi lớn nhất chưa chắc là bước đáng sửa nhất — cần so với lịch sử.
- Trả lời kèm giả thuyết và cách đo, không chỉ con số.
Use ← → to move between lessons