Tôi đã có một bảng progresses
(chứa theo thứ tự hàng trăm ngàn bản ghi hiện tại):
Column | Type | Modifiers
---------------+-----------------------------+---------------------------------------------------------
id | integer | not null default nextval('progresses_id_seq'::regclass)
lesson_id | integer |
user_id | integer |
created_at | timestamp without time zone |
deleted_at | timestamp without time zone |
Indexes:
"progresses_pkey" PRIMARY KEY, btree (id)
"index_progresses_on_deleted_at" btree (deleted_at)
"index_progresses_on_lesson_id" btree (lesson_id)
"index_progresses_on_user_id" btree (user_id)
và một khung nhìn v_latest_progresses
truy vấn gần đây nhất progress
bởi user_id
và lesson_id
:
SELECT DISTINCT ON (progresses.user_id, progresses.lesson_id)
progresses.id AS progress_id,
progresses.lesson_id,
progresses.user_id,
progresses.created_at,
progresses.deleted_at
FROM progresses
WHERE progresses.deleted_at IS NULL
ORDER BY progresses.user_id, progresses.lesson_id, progresses.created_at DESC;
Người dùng có thể có nhiều tiến bộ cho bất kỳ bài học cụ thể nào, nhưng chúng tôi thường muốn truy vấn một tập các tiến trình được tạo gần đây nhất cho một nhóm người dùng hoặc bài học nhất định (hoặc kết hợp cả hai).
Chế độ xem v_latest_progresses
thực hiện điều này độc đáo và thậm chí còn hiệu quả khi tôi chỉ định một bộ user_id
s:
# EXPLAIN SELECT "v_latest_progresses".* FROM "v_latest_progresses" WHERE "v_latest_progresses"."user_id" IN ([the same list of ids given by the subquery in the second example below]);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Unique (cost=526.68..528.66 rows=36 width=57)
-> Sort (cost=526.68..527.34 rows=265 width=57)
Sort Key: progresses.user_id, progresses.lesson_id, progresses.created_at
-> Index Scan using index_progresses_on_user_id on progresses (cost=0.47..516.01 rows=265 width=57)
Index Cond: (user_id = ANY ('{ [the above list of user ids] }'::integer[]))
Filter: (deleted_at IS NULL)
(6 rows)
Tuy nhiên, nếu tôi cố gắng thực hiện cùng một truy vấn thay thế tập hợp user_id
s bằng truy vấn con, nó sẽ trở nên rất kém hiệu quả:
# EXPLAIN SELECT "v_latest_progresses".* FROM "v_latest_progresses" WHERE "v_latest_progresses"."user_id" IN (SELECT "users"."id" FROM "users" WHERE "users"."company_id"=44);
QUERY PLAN
-----------------------------------------------------------------------------------------------------
Merge Semi Join (cost=69879.08..72636.12 rows=19984 width=57)
Merge Cond: (progresses.user_id = users.id)
-> Unique (cost=69843.45..72100.80 rows=39969 width=57)
-> Sort (cost=69843.45..70595.90 rows=300980 width=57)
Sort Key: progresses.user_id, progresses.lesson_id, progresses.created_at
-> Seq Scan on progresses (cost=0.00..31136.31 rows=300980 width=57)
Filter: (deleted_at IS NULL)
-> Sort (cost=35.63..35.66 rows=10 width=4)
Sort Key: users.id
-> Index Scan using index_users_on_company_id on users (cost=0.42..35.46 rows=10 width=4)
Index Cond: (company_id = 44)
(11 rows)
Điều tôi đang cố gắng tìm hiểu là tại sao PostgreSQL muốn thực hiện DISTINCT
truy vấn trên toàn bộ progresses
bảng trước khi nó lọc theo truy vấn con trong ví dụ thứ hai.
Có ai có lời khuyên nào về cách cải thiện truy vấn này không?
144.07..144.6
, CÁCH dưới 70.000 tôi đã nhận được! Cảm ơn rât nhiều.