我有一个包含 ~ 100.000.000 条记录的表。在此表中,有一个 varchar(30) 列,其中包含汽车牌照。我正在将此表与另一个包含相同数量记录的表连接起来。
我需要使用具有不同值的 like 查询此表,并使用连接表中的列对结果进行排序:
select *
from a left join b on a.id = b.id
where a.license_plate ilike any ('{"GD47%", "CD529%", "CX7530_", "GL573S_"}')
order by b.date
b.date 列上有一个标准索引(btree),a.license_plate 列上有一个 gist 和一个标准 btree 索引。
我仅在类似操作中使用某些值时遇到性能问题。 例如使用这个查询:
select *
from a left join b on a.c_id_msg = b.c_id_msg
where a.c_tar ilike any ('{"AB142%"}')
order by b.date
至少需要20分钟。
性能看起来非常随机,有些值需要几毫秒,有些需要几分钟。 我看到的唯一相关性是,需要较长时间的输入由至少 5 个字符组成,字符串末尾有一个 %。
如果我删除 order by 子句,执行查询只需要几秒钟。
以下是带有 order by 子句和 5 个字符输入的查询的查询规划器结果:
Limit (cost=1001.16..59950.24 rows=10 width=274)
-> Gather Merge (cost=1001.16..48020923.65 rows=8146 width=274)
Workers Planned: 2
-> Nested Loop (cost=1.14..48018983.37 rows=3394 width=274)
-> Parallel Index Scan Backward using index_btree on b (cost=0.57..22944880.81 rows=37045867 width=204)
-> Index Scan using index_gist on a (cost=0.57..0.68 rows=1 width=70)
Index Cond: (c_id_msg = a.c_id_msg)
Filter: (((c_tar)::text ~~* ANY ('{AB142%}'::text[])) AND ((c_tip_ric)::text = 'FNL'::text))
此处插入的是没有 order by 子句和 5 个字符输入的查询的查询规划器结果:
Limit (cost=431.81..565.35 rows=10 width=274)
-> Nested Loop (cost=431.81..109212.18 rows=8146 width=274)
-> Bitmap Heap Scan on a (cost=431.24..34898.28 rows=8687 width=70)
Recheck Cond: ((c_tar)::text ~~* ANY ('{AB142%}'::text[]))
Filter: ((c_tip_ric)::text = 'FNL'::text)
-> Bitmap Index Scan on index_gist (cost=0.00..429.07 rows=9153 width=0)
Index Cond: ((c_tar)::text ~~* ANY ('{AB142%}'::text[]))
-> Index Scan using b_pkey on b (cost=0.57..8.55 rows=1 width=204)
Index Cond: (c_id_msg = a.c_id_msg)
最后,这是带有 order by 子句和 3 个输入字符的查询的查询规划器结果:
Limit (cost=1001.16..59950.24 rows=10 width=274)
-> Gather Merge (cost=1001.16..48020923.65 rows=8146 width=274)
Workers Planned: 2
-> Nested Loop (cost=1.14..48018983.37 rows=3394 width=274)
-> Parallel Index Scan Backward using index_btree on b (cost=0.57..22944880.81 rows=37045867 width=204)
-> Index Scan using index_gist on a (cost=0.57..0.68 rows=1 width=70)
Index Cond: (c_id_msg = a.c_id_msg)
Filter: (((c_tar)::text ~~* ANY ('{AB142%}'::text[])) AND ((c_tip_ric)::text = 'FNL'::text))
有没有办法提高此类查询的性能?我是不是做错了什么?
我尝试使用不同的算法添加不同的索引,但结果似乎相同。
尝试使用 CTE,这样排序应该更便宜,例如:
WITH mydata AS (SELECT a.*,b.date AS bdate
FROM a left join b on a.c_id_msg = b.c_id_msg
WHERE a.c_tar ilike any ('{"AB142%"}') )
SELECT mydata.* ORDER BY mydata.bdate;