我有以下数据模型:
包含~310M行的父表:
Table parent:
Column | Type
------------+-------------------------------
id | BIGINT (Primary key, sequence)
type | VARCHAR
group | VARCHAR
date | TIMESTAMP
isok | BOOLEAN
With an index on (group,isok) where isok = false
和一个〜1000M行的孩子:
Table child
Column | Type
------------+-------------------------------
parentid | BIGINT (Foreign Key)
field1 | VARCHAR
field2 | VARCHAR
With an index on (parentid)
1父母可以有0到N个孩子。
我需要执行此查询:
SELECT p.id, p.type, p.date, c.field1, c.field2
FROM parent p
LEFT OUTER JOIN child AS c ON p.id = c.parentid
WHERE group = 'groupname' AND isok = false;
EXPLAIN ANALYZE告诉我查询计划是:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Hash Right Join (cost=223072.57..34724441.40 rows=698363 width=65) (actual time=7944.249..933430.677 rows=286257 loops=1)
Hash Cond: (c.parentid = p.id)
-> Seq Scan on child c (cost=0.00..23840617.04 rows=1217573504 width=47) (actual time=0.005..488678.149 rows=1217573499 loops=1)
-> Hash (cost=220871.38..220871.38 rows=176095 width=26) (actual time=206.169..206.169 rows=283686 loops=1)
Buckets: 32768 Batches: 1 Memory Usage: 17731kB
-> Index Scan using parent_group_nok_idx on parent p (cost=0.55..220871.38 rows=176095 width=26) (actual time=0.032..115.183 rows=283686 loops=1)
Index Cond: (((group)::text = 'groupname'::text) AND (isok = false))
Total runtime: 933486.035 ms
当我禁用seqscans时:
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop Left Join (cost=1.13..35309490.28 rows=698363 width=65) (actual time=0.684..42144.558 rows=286257 loops=1)
-> Index Scan using parent_group_nok_idx on parent p (cost=0.55..220871.38 rows=176095 width=26) (actual time=0.030..122.959 rows=283686 loops=1)
Index Cond: (((group)::text = 'groupname'::text) AND (isok = false))
-> Index Scan using child_parentid_idx on child c (cost=0.58..184.74 rows=1452 width=47) (actual time=0.145..0.147 rows=1 loops=283686)
Index Cond: (parentid = p.id)
Total runtime: 42200.478 ms
我可以做什么(禁用seq扫描除外)“强制”优化器选择索引方式?
答案 0 :(得分:3)
在查找类似问题并阅读本文后:trumping-the-postgresql-query-planner,我尝试使用CTE查询:这是我使用的查询:
WITH cte AS (
SELECT id, type, date
FROM parent
WHERE group = 'groupname' AND isok = false
ORDER BY id ASC
)
SELECT cte.id, cte.type, cte.date, c.field1, c.field2
FROM cte LEFT OUTER JOIN child c ON c.parentid = cte.id;
现在,有查询计划:
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop Left Join (cost=236655.35..33098268.28 rows=238777013 width=56) (actual time=243.160..1473.618 rows=286257 loops=1)
CTE cte
-> Sort (cost=236214.54..236654.77 rows=176095 width=26) (actual time=243.135..314.067 rows=283686 loops=1)
Sort Key: e.id
Sort Method: quicksort Memory: 34451kB
-> Index Scan using parent_group_nok_idx on parent (cost=0.55..220871.38 rows=176095 width=26) (actual time=0.041..113.058 rows=283686 loops=1)
Index Cond: (((group)::text = 'groupname'::text) AND (isok = false))
-> CTE Scan on cte (cost=0.00..3521.90 rows=176095 width=18) (actual time=243.140..449.385 rows=283686 loops=1)
-> Index Scan using child_parentid_idx on child c (cost=0.58..173.03 rows=1356 width=46) (actual time=0.002..0.003 rows=1 loops=283686)
Index Cond: (parentid = cte.id)
Total runtime: 1526.945 ms
现在使用我的索引。