Postgresql Postgres执行计划where条款的命令和命令依据

Postgresql Postgres执行计划where条款的命令和命令依据,postgresql,sql-execution-plan,Postgresql,Sql Execution Plan,我有一个非常简单的SQL: select * from email.email_task where acquire_time < now() and state IN ('CREATED', 'RELEASED') order by creation_time asc limit 1; 从email.email\u任务中选择*,其中获取时间排序(成本=187404.36..190753.58行=1339690宽度=743) 排序键:创建时间 ->电子邮件任务上的顺序扫描(成本=0.00

我有一个非常简单的SQL:

select * from email.email_task where acquire_time < now() and state IN ('CREATED', 'RELEASED') order by creation_time asc limit 1;
从email.email\u任务中选择*,其中获取时间
我创建了两个索引:

  • 状态指数
  • 状态索引、获取时间、创建时间
  • 理想情况下,我认为Postgres应该选择第二个,因为它匹配此SQL中所需的每一列:

    但是,执行计划显示的情况不同,它不使用以下两个索引:

    Limit  (cost=187404.36..187404.36 rows=1 width=743)
       ->  Sort  (cost=187404.36..190753.58 rows=1339690 width=743)
             Sort Key: creation_time
             ->  Seq Scan on email_task  (cost=0.00..180705.91 rows=1339690 width=743)
                   Filter: (((state)::text = 'CREATED'::text) AND (acquire_time < now()))
    
    限制(成本=187404.36..187404.36行=1宽=743)
    ->排序(成本=187404.36..190753.58行=1339690宽度=743)
    排序键:创建时间
    ->电子邮件任务上的顺序扫描(成本=0.00..180705.91行=1339690宽度=743)
    筛选器:((状态)::text='CREATED'::text)和(acquire_time
    我知道,如果返回的行数达到总数的10%,那么它将选择Seq扫描而不是索引扫描。(详情请参阅 )这就是为什么不选择index1

    我不明白的是,既然index2匹配所有列,为什么不选择index2

    然后我尝试了第三个索引:

  • 创建时间、获取时间、状态的索引
  • 这次它使用index3(我使用另一个较小的数据库添加索引) 性能1,因为原来的一个有200万行,需要花费太多时间)

    限制(成本=0.29..0.36行=1宽度=75)(实际时间=0.043..0.043行=1圈=1)
    ->在电子邮件任务上使用性能1进行索引扫描(成本=0.29..763.76行=9998宽度=75)(实际时间=0.042..0.042行=1循环=1)
    索引条件:(获取时间<现在()
    筛选器:((状态)::text=ANY(“{CREATED,RELEASED}”::text[]))
    
    似乎Postgres execution planner首先选择order by子句,然后选择where子句,这有点违反直觉

    我的理解正确吗?或者还有其他一些因素会影响博士后计划员


    提前感谢。

    最后一个使用
    acquire\u time
    索引的查询计划与您声称的索引完全不同。此外,该计划不包含排序条件,因此对于该计划,未使用排序依据。也就是说,第三个查询计划与您提供的查询无关。对于未使用的第二个索引,是因为其中两列位于WHERE中,1列按顺序排列,因此您有一个索引。为了在所有条件下启动第二个索引,必须在相同的“级别”上存在。意思是,例如,所有3列都在WHERE.Hi@KristoMägi。感谢您的评论,第三个查询计划使用了“perf_1”索引,即(创建时间、获取时间、状态)。获取时间实际上是列名。我确认SQL中使用了Order By:
    explain analyze select*from email.email\u任务,其中获取时间
    使用索引
    acquire\u time
    的最后一个查询计划中说明您所做的索引。此外,该计划不包含排序条件,因此对于该计划,未使用排序依据。也就是说,第三个查询计划与您提供的查询无关。对于未使用的第二个索引,是因为其中两列位于WHERE中,1列按顺序排列,因此您有一个索引。为了在所有条件下启动第二个索引,必须在相同的“级别”上存在。意思是,例如,所有3列都在WHERE.Hi@KristoMägi。感谢您的评论,第三个查询计划使用了“perf_1”索引,即(创建时间、获取时间、状态)。获取时间实际上是列名。我确认在SQL中使用了Order By:
    explain analyze select*from email.email\u任务,其中获取时间Limit  (cost=0.29..0.36 rows=1 width=75) (actual time=0.043..0.043 rows=1 loops=1)
       ->  Index Scan using perf_1 on email_task  (cost=0.29..763.76 rows=9998 width=75) (actual time=0.042..0.042 rows=1 loops=1)
             Index Cond: (acquire_time < now())
             Filter: ((state)::text = ANY ('{CREATED,RELEASED}'::text[]))