如何优化在postgresql 10.3中使用seqscan的查询?

如何优化在postgresql 10.3中使用seqscan的查询?,sql,postgresql,left-join,query-optimization,Sql,Postgresql,Left Join,Query Optimization,我的应用程序中有两个表 唯一警报 警报 我的警报表有一百万行,唯一警报表有40000行,我希望找到所有触发的警报 select * from unique_alerts u INNER JOIN alerts a ON u.asset_id=a.asset_id WHERE u.current_price > a.alert_price AND a.direction=true OR u.current_price <= a.alert_price AND a.direction

我的应用程序中有两个表

唯一警报

警报

我的警报表有一百万行,唯一警报表有40000行,我希望找到所有触发的警报

select * from unique_alerts u
INNER JOIN alerts a
ON u.asset_id=a.asset_id
WHERE u.current_price > a.alert_price 
AND a.direction=true
OR u.current_price <= a.alert_price 
AND a.direction=false
当我在这个查询上运行explain analyze时,我看到两个顺序扫描,我在a.asset_id上定义了一个索引,它没有被使用

"Hash Join  (cost=1248.49..34977.79 rows=270686 width=72) (actual time=37.698..713.334 rows=21825 loops=1)"
"  Hash Cond: ((a.pair)::text = (u._id)::text)"
"  Join Filter: (((u.current_price > a.alert_price) AND a.direction) OR ((u.current_price <= a.alert_price) AND (NOT a.direction)))"
"  Rows Removed by Join Filter: 857192"
"  ->  Seq Scan on alerts a  (cost=0.00..20490.00 rows=751170 width=52) (actual time=0.014..158.984 rows=1000000 loops=1)"
"        Filter: (direction OR (NOT direction))"
"  ->  Hash  (cost=711.55..711.55 rows=42955 width=20) (actual time=37.528..37.528 rows=42955 loops=1)"
"        Buckets: 65536  Batches: 1  Memory Usage: 2766kB"
"        ->  Seq Scan on unique_alerts u  (cost=0.00..711.55 rows=42955 width=20) (actual time=0.007..4.891 rows=42955 loops=1)"
"Planning time: 0.781 ms"
"Execution time: 714.892 ms"
我如何确保索引a.asset_id正在使用,如果有,我还需要什么索引?另外,如果我必须多次运行此连接,视图会更好吗?谢谢,OR可能会让乐观主义者感到困难

一个选项是使用UNIONALL来允许两个查询计划

SELECT * FROM unique_alerts u
INNER JOIN alerts a
ON u.asset_id=a.asset_id
WHERE u.current_price > a.alert_price AND a.direction=true

UNION ALL

SELECT * FROM unique_alerts u
INNER JOIN alerts a
ON u.asset_id=a.asset_id
WHERE u.current_price <= a.alert_price AND a.direction=false
如果你要这么做,我建议你建立一个预警综合指数:方向、资产id、预警价格


这样的索引将更容易缩小适当的行范围。

视图本身不会改变执行时间。将视图视为宏。存在实际存储查询结果的实体化视图,实际上是缓存。这是否是一个好主意取决于您读取数据的频率和写入数据的频率。谢谢,但是如果必须每2分钟加入一次,视图不会在插入发生在两个表中时进行连接,并保持更新,以便我每次只需查询而不必加入,对不起,postgres中的一位新手,此外,如果在这两个表中删除了任何条目,我是否需要一个触发器来更新视图,或者它是否会自动更新自身?否,视图实际上只是一个宏。视图不存储任何内容。实体化视图是一种在基础数据每次更改时缓存查询结果的方法。如果你读数据的频率明显高于写数据的频率,你可能会看到一个好处。但是,在你证明确实有一个问题需要解决之前,不要陷入优化的泥潭。过早的优化吸引了极客,但带来的问题比解决的问题还多。首先关注良好的工程设计,只有在绝对需要时才进行优化。谢谢!我一定会记住这句话,过早优化是所有问题的根源evil@pirateapp-变更后的执行时间是多少?您是否评估了新索引对将数据写入表的任何内容的影响?您将降低任何写入操作的速度,但希望比使用它节省的时间少。这需要更多的时间,因为它涉及两次连续扫描。我还注意到索引的一些方面,price值上的索引似乎是多余的,因为每一行都会有不同的price值,所以u.current_price和a.alert_price不适合索引,db大小为82 mb,有100万行,索引大小为117 mb,有3个索引,数据库自然不使用这些索引,我想PG优化器很聪明地认识到这一点,顺便说一下,数据库是否考虑了A.AsExtIID中的索引,如果在联接子句中指定了索引,那么我不认为其他字段是indexable@PirateApp-那么我怀疑您创建了三个索引,我建议您创建一个包含三个字段的索引?使用方向、资产id、警报价格上的复合索引,由于WHERE子句,优化者可以为每个查询消除整整一半的索引。然后,根据资产(主要连接谓词)对索引进行进一步排序,然后根据警报价格进行排序,从而允许范围查找。即使这仍然会导致两次扫描,它扫描了半个表,然后扫描了另一半…创建指数价格指数警报方向,资产id,警报价格是一个单一的综合指数,不是吗?我想你已经调用创建索引3次了,但我没有这样做
"Hash Join  (cost=1248.49..34977.79 rows=270686 width=72) (actual time=37.698..713.334 rows=21825 loops=1)"
"  Hash Cond: ((a.pair)::text = (u._id)::text)"
"  Join Filter: (((u.current_price > a.alert_price) AND a.direction) OR ((u.current_price <= a.alert_price) AND (NOT a.direction)))"
"  Rows Removed by Join Filter: 857192"
"  ->  Seq Scan on alerts a  (cost=0.00..20490.00 rows=751170 width=52) (actual time=0.014..158.984 rows=1000000 loops=1)"
"        Filter: (direction OR (NOT direction))"
"  ->  Hash  (cost=711.55..711.55 rows=42955 width=20) (actual time=37.528..37.528 rows=42955 loops=1)"
"        Buckets: 65536  Batches: 1  Memory Usage: 2766kB"
"        ->  Seq Scan on unique_alerts u  (cost=0.00..711.55 rows=42955 width=20) (actual time=0.007..4.891 rows=42955 loops=1)"
"Planning time: 0.781 ms"
"Execution time: 714.892 ms"
SELECT * FROM unique_alerts u
INNER JOIN alerts a
ON u.asset_id=a.asset_id
WHERE u.current_price > a.alert_price AND a.direction=true

UNION ALL

SELECT * FROM unique_alerts u
INNER JOIN alerts a
ON u.asset_id=a.asset_id
WHERE u.current_price <= a.alert_price AND a.direction=false