sql查询postgres计数嵌套循环糟糕的表现

时间:2017-11-06 03:29:10

标签: sql postgresql query-performance

您好我似乎找不到合适的答案所以我不妨写一篇文章

任何数据库专家都可以帮助我改进以下查询(请参阅解释计划),这会大大减慢我们的生产应用程序。

  • 出价与房地产有关
  • 房地产由代理商拥有
  • 我正在使用postgres
  • 表存储每个用户的视图:HIT(user_id,bid_id,date)

目的是检索a的每次出价的点击次数    特定机构

这是查询

select hit.bid_id , count(hit.id)
from hit
  cross join bid
  cross join realty
where hit.bid_id=bid.id
  and realty.id=bid.realty_id
  and realty.agency_id = 91
group by hit.bid_id
order by count(hit.id) desc

这是解释计划

"Sort  (cost=167474.69..167493.30 rows=7445 width=16)"
"  Sort Key: (count(hit.id)) DESC"
"  ->  HashAggregate  (cost=166921.45..166995.90 rows=7445 width=16)"
"        Group Key: hit.bid_id"
"        ->  Nested Loop  (cost=694.81..162541.34 rows=876021 width=16)"
"              ->  Hash Join  (cost=694.38..7217.46 rows=1986 width=8)"
"                    Hash Cond: (bid.realty_id = realty.id)"
"                    ->  Seq Scan on bid  (cost=0.00..6398.98 rows=27798 width=16)"
"                    ->  Hash  (cost=669.92..669.92 rows=1957 width=8)"
"                          ->  Bitmap Heap Scan on realty  (cost=63.45..669.92 rows=1957 width=8)"
"                                Recheck Cond: (agency_id = 91)"
"                                ->  Bitmap Index Scan on agency_idx  (cost=0.00..62.97 rows=1957 width=0)"
"                                      Index Cond: (agency_id = 91)"
"              ->  Index Scan using hit_bid_id_idx on hit  (cost=0.43..61.74 rows=1647 width=16)"
"                    Index Cond: (bid_id = bid.id)"

我尝试使用exists,或者选择但是它们更糟糕

[编辑] 我正在使用QueryDsl(java api)生成交叉连接,但即使使用内连接,执行计划也太长, 这是详细的解释计划

"Sort  (cost=169479.60..169498.99 rows=7756 width=16) (actual time=15350.858..15351.819 rows=821 loops=1)"
"  Output: hit.bid_id, (count(hit.id))"
"  Sort Key: (count(hit.id)) DESC"
"  Sort Method: quicksort  Memory: 63kB"
"  ->  HashAggregate  (cost=168900.96..168978.52 rows=7756 width=16) (actual time=15348.418..15349.550 rows=821 loops=1)"
"        Output: hit.bid_id, count(hit.id)"
"        Group Key: hit.bid_id"
"        ->  Nested Loop  (cost=699.70..164385.85 rows=903022 width=16) (actual time=17.777..14364.165 rows=582723 loops=1)"
"              Output: hit.bid_id, hit.id"
"              ->  Hash Join  (cost=699.26..7225.23 rows=2013 width=8) (actual time=8.427..146.966 rows=1977 loops=1)"
"                    Output: bid.id"
"                    Hash Cond: (bid.realty_id = realty.id)"
"                    ->  Seq Scan on public.bid  (cost=0.00..6400.88 rows=27988 width=16) (actual time=0.018..84.389 rows=27994 loops=1)"
"                          Output: bid.id, bid.created_by, bid.created_date, bid.last_modified_by, bid.last_modified_date, bid.agency_costs, bid.availability_begin_date, bid.availability_end_date, bid.bail, bid.description, bid.imported_bid, bid.is_availabl (...)"
"                    ->  Hash  (cost=674.46..674.46 rows=1984 width=8) (actual time=8.186..8.186 rows=1977 loops=1)"
"                          Output: realty.id"
"                          Buckets: 2048  Batches: 1  Memory Usage: 94kB"
"                          ->  Bitmap Heap Scan on public.realty  (cost=67.66..674.46 rows=1984 width=8) (actual time=0.533..4.967 rows=1977 loops=1)"
"                                Output: realty.id"
"                                Recheck Cond: (realty.agency_id = 91)"
"                                Heap Blocks: exact=208"
"                                ->  Bitmap Index Scan on agency_idx  (cost=0.00..67.17 rows=1984 width=0) (actual time=0.491..0.491 rows=1978 loops=1)"
"                                      Index Cond: (realty.agency_id = 91)"
"              ->  Index Scan using hit_bid_id_idx on public.hit  (cost=0.43..61.88 rows=1619 width=16) (actual time=2.198..6.376 rows=295 loops=1977)"
"                    Output: hit.id, hit.created_by, hit.created_date, hit.last_modified_by, hit.last_modified_date, hit.date, hit.ip, hit.user_id, hit.bid_id, hit.display_phone"
"                    Index Cond: (hit.bid_id = bid.id)"
"Planning time: 3.037 ms"
"Execution time: 15353.187 ms"

表DDL

CREATE TABLE public.bid
(
  id bigint NOT NULL,
  realty_id bigint,
  CONSTRAINT bid_pkey PRIMARY KEY (id),
  CONSTRAINT bid_fkey_realty FOREIGN KEY (realty_id)
      REFERENCES public.realty (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE public.hit
(
  id bigint NOT NULL,
  bid_id bigint,
  CONSTRAINT hit_pkey PRIMARY KEY (id),
  CONSTRAINT hit_fkey_bid FOREIGN KEY (bid_id)
      REFERENCES public.bid (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE public.realty
(
  id bigint NOT NULL,
  CONSTRAINT realty_pkey PRIMARY KEY (id)
)

2 个答案:

答案 0 :(得分:0)

您不必要地使用交叉连接,除此之外还有一个" seq扫描"在您的解释计划的投标表上;但以下的解释计划可能有所不同:

select hit.bid_id , count(hit.id)
from hit
  inner join bid ON hit.bid_id=bid.id
  inner join realty ON realty.id=bid.realty_id
where realty.agency_id = 91
group by hit.bid_id
order by count(hit.id) desc

虽然没关系,但是改变表序列会产生影响:

select hit.bid_id , count(hit.id)
from realty
  inner join bid ON realty.id=bid.realty_id
  inner join hit ON hit.bid_id=bid.id
where realty.agency_id = 91
group by hit.bid_id
order by count(hit.id) desc

我可以假设数据库统计信息是最新的还是新的"?

答案 1 :(得分:0)

如果您提供更多信息(例如索引状态,表格描述,解释计划以及更多详细信息选项),我会建议更有趣的解决方案。 但好的解决方案将由其他人提供。我提供了不好的解决方案,但它有时会有所帮助。

此源基于Java,但它适用于其他语言。

这是一项临时工作,但您可能会立即生效。

尝试用于测试非nestloop执行计划。

PreparedStatement stmt = connect.preparedStatement(
"SET enable_nestloop TO false;" +
"select hit.bid_id , count(hit.id)
from hit
cross join bid
cross join realty
where hit.bid_id=bid.id
and realty.id=bid.realty_id
and realty.agency_id = 91
group by hit.bid_id
order by count(hit.id) desc;" +
"SET enable_nestloop TO true;"
);