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_progressestruy vấn gần đây nhất progressbởi user_idvà 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_progressesthự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_ids:
# 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_ids 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 DISTINCTtruy vấn trên toàn bộ progressesbả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.