我有3张桌子:
create table cart (
id bigserial primary key,
buyer_id bigint unique not null
);
create table contact_person (
id bigserial primary key,
cart_id bigint references cart (id) not null unique,
phone_number jsonb,
first_name VARCHAR,
middle_name VARCHAR,
last_name VARCHAR
);
create table cart_items (
id bigserial primary key,
item_id bigint not null,
cart_id bigint references cart (id) not null,
count int not null,
unique (item_id, cart_id)
);
购物车:contact_person与 1:1
相关
cart:cart_items 1:N
我想按购物车ID汇总所有cart_items字段。 有2个选项:
1)在加入之前进行汇总:
select c.id as id,
c.buyer_id as buyer_id,
cp.id as contact_id,
cp.phone_number,
cp.first_name,
cp.middle_name,
cp.last_name,
ci.ids, ci.item_ids, ci.counts
from cart c
inner join contact_person cp on c.id = cp.cart_id
left join (select cart_id, array_agg(id) as ids, array_agg(item_id) as item_ids, array_agg(count) as counts
from cart_items ci
group by cart_id) ci on ci.cart_id = c.id
where c.buyer_id = :buyerId;
2)加入后汇总:
select c.id as id,
c.buyer_id as buyer_id,
cp.id as contact_id,
cp.phone_number,
cp.first_name,
cp.middle_name,
cp.last_name,
array_agg(ci.id) as ids,
array_agg(ci.item_id) as item_ids,
array_agg(ci.count) as counts
from cart c
inner join contact_person cp on c.id = cp.cart_id
left join cart_items ci on ci.cart_id = c.id
where c.buyer_id = :buyerId
group by c.id, cp.id;
正如Explain所示,联接后具有聚合的查询要快得多。 查询计划实际上是不同的,但是我无法解释为什么在聚合之前要花费如此高的成本。
1)之前汇总:
Nested Loop (cost=108.97..141.16 rows=1 width=248)
-> Merge Left Join (cost=108.82..132.96 rows=1 width=112)
Merge Cond: (c.id = ci.cart_id)
-> Sort (cost=8.18..8.19 rows=1 width=16)
Sort Key: c.id
-> Index Scan using cart_buyer_id_key on cart c (cost=0.15..8.17 rows=1 width=16)
Index Cond: (buyer_id = 1)
-> GroupAggregate (cost=100.64..122.26 rows=200 width=104)
Group Key: ci.cart_id
-> Sort (cost=100.64..104.26 rows=1450 width=28)
Sort Key: ci.cart_id
-> Seq Scan on cart_items ci (cost=0.00..24.50 rows=1450 width=28)
-> Index Scan using contact_person_cart_id_key on contact_person cp (cost=0.15..8.17 rows=1 width=144)
Index Cond: (cart_id = c.id)
2)在以下时间聚合:
GroupAggregate (cost=41.62..41.66 rows=1 width=248)
Group Key: c.id, cp.id
-> Sort (cost=41.62..41.63 rows=1 width=172)
Sort Key: c.id, cp.id
-> Nested Loop Left Join (cost=15.33..41.61 rows=1 width=172)
-> Nested Loop (cost=0.30..16.37 rows=1 width=152)
-> Index Scan using cart_buyer_id_key on cart c (cost=0.15..8.17 rows=1 width=16)
Index Cond: (buyer_id = 1)
-> Index Scan using contact_person_cart_id_key on contact_person cp (cost=0.15..8.17 rows=1 width=144)
Index Cond: (cart_id = c.id)
-> Bitmap Heap Scan on cart_items ci (cost=15.03..25.17 rows=7 width=28)
Recheck Cond: (cart_id = c.id)
-> Bitmap Index Scan on cart_items_item_id_cart_id_key (cost=0.00..15.03 rows=7 width=0)
Index Cond: (cart_id = c.id)
我想在cart_id字段上添加一个对cart_items的索引,这有效地加速了查询,但是在第一种情况下,就像在第二种情况下那样。 您如何解释这种差异?
答案 0 :(得分:1)
这样想:在您之前的示例中,您正在联接一个表和一个“运行中”视图,必须在联接之前将其生成。
在您的“之后”示例中,您要联接2个表,然后进行汇总。联接本身更快,不需要创建,排序等。在不删除任何行的情况下汇总所有数据后,它应该会更快。而且无论如何联接都非常简单。