Postgresql 使用参数而不是硬编码字符串时,Postgres查询速度非常慢

Postgresql 使用参数而不是硬编码字符串时,Postgres查询速度非常慢,postgresql,symfony,doctrine-orm,postgresql-9.1,sql-execution-plan,Postgresql,Symfony,Doctrine Orm,Postgresql 9.1,Sql Execution Plan,我遇到了这个Postgres问题,如果我在查询字符串上使用参数而不是硬编码它的值,那么执行同一个查询需要很长时间。列名为“media_type”,是一个VARCHAR(20)。我使用Symfony2和Doctrine2 ORM从PHP运行这些查询,该表有大约1.000.000条记录 我的查询有问题吗?这可能是Postgres的配置问题吗 1-媒体类型的硬编码值 duration: 5.365 ms parse pdo_stmt_00000001: SELECT id,site_id FROM

我遇到了这个Postgres问题,如果我在查询字符串上使用参数而不是硬编码它的值,那么执行同一个查询需要很长时间。列名为“media_type”,是一个VARCHAR(20)。我使用Symfony2和Doctrine2 ORM从PHP运行这些查询,该表有大约1.000.000条记录

我的查询有问题吗?这可能是Postgres的配置问题吗

1-媒体类型的硬编码值

duration: 5.365 ms  parse pdo_stmt_00000001: SELECT id,site_id FROM item where media_type = 'Collection' AND enabled = 'true' AND site_id = $1 AND user_id = $2 ORDER BY id DESC LIMIT $3 OFFSET $4
duration: 0.142 ms  bind pdo_stmt_00000001: SELECT id,site_id FROM item where media_type = 'Collection' AND enabled = 'true' AND site_id = $1 AND user_id = $2 ORDER BY id DESC LIMIT $3 OFFSET $4
parameters: $1 = '1', $2 = '1', $3 = '100', $4 = '0'
duration: 8.667 ms  execute pdo_stmt_00000001: SELECT id,site_id FROM item where media_type = 'Collection' AND enabled = 'true' AND site_id = $1 AND user_id = $2 ORDER BY id DESC LIMIT $3 OFFSET $4
parameters: $1 = '1', $2 = '1', $3 = '100', $4 = '0'
执行计划:

duration: 8.640 ms  plan:
    Query Text: SELECT id,site_id FROM item where media_type = 'Collection' AND enabled = 'true' AND site_id = $1 AND user_id = $2 ORDER BY id DESC LIMIT $3 OFFSET $4
    Limit  (cost=8.38..8.38 rows=1 width=12) (actual time=8.516..8.595 rows=24 loops=1)
      Buffers: shared hit=10 read=15
        ->  Sort  (cost=8.38..8.38 rows=1 width=12) (actual time=8.505..8.530 rows=24 loops=1)
            Sort Key: id
            Sort Method: quicksort  Memory: 26kB
            Buffers: shared hit=10 read=15
            ->  Index Scan using item_media_type_index on item  (cost=0.00..8.37 rows=1 width=12) (actual time=7.955..8.397 rows=24 loops=1)
                    Index Cond: ((media_type)::text = 'Collection'::text)
                    Filter: (enabled AND (site_id = $1) AND (user_id = $2))
                    Buffers: shared hit=8 read=15
duration: 71564.922 ms  plan:
    Query Text: SELECT id,site_id FROM item where media_type = $1 AND enabled = 'true' AND site_id = $2 AND user_id = $3 ORDER BY id DESC LIMIT $4 OFFSET $5
    Limit  (cost=90663.16..181326.31 rows=17184 width=12) (actual time=3.667..71564.864 rows=24 loops=1)
      Buffers: shared hit=183786 read=96585
        ->  Index Scan Backward using item_pkey on item  (cost=0.00..906610.46 rows=171836 width=12) (actual time=3.655..71564.798 rows=24 loops=1)
               Filter: (enabled AND ((media_type)::text = $1) AND (site_id = $2) AND (user_id = $3))
               Buffers: shared hit=183786 read=96585
2-使用媒体类型参数(较慢)

执行计划:

duration: 8.640 ms  plan:
    Query Text: SELECT id,site_id FROM item where media_type = 'Collection' AND enabled = 'true' AND site_id = $1 AND user_id = $2 ORDER BY id DESC LIMIT $3 OFFSET $4
    Limit  (cost=8.38..8.38 rows=1 width=12) (actual time=8.516..8.595 rows=24 loops=1)
      Buffers: shared hit=10 read=15
        ->  Sort  (cost=8.38..8.38 rows=1 width=12) (actual time=8.505..8.530 rows=24 loops=1)
            Sort Key: id
            Sort Method: quicksort  Memory: 26kB
            Buffers: shared hit=10 read=15
            ->  Index Scan using item_media_type_index on item  (cost=0.00..8.37 rows=1 width=12) (actual time=7.955..8.397 rows=24 loops=1)
                    Index Cond: ((media_type)::text = 'Collection'::text)
                    Filter: (enabled AND (site_id = $1) AND (user_id = $2))
                    Buffers: shared hit=8 read=15
duration: 71564.922 ms  plan:
    Query Text: SELECT id,site_id FROM item where media_type = $1 AND enabled = 'true' AND site_id = $2 AND user_id = $3 ORDER BY id DESC LIMIT $4 OFFSET $5
    Limit  (cost=90663.16..181326.31 rows=17184 width=12) (actual time=3.667..71564.864 rows=24 loops=1)
      Buffers: shared hit=183786 read=96585
        ->  Index Scan Backward using item_pkey on item  (cost=0.00..906610.46 rows=171836 width=12) (actual time=3.655..71564.798 rows=24 loops=1)
               Filter: (enabled AND ((media_type)::text = $1) AND (site_id = $2) AND (user_id = $3))
               Buffers: shared hit=183786 read=96585

提前感谢。

有一次,当我绑定到SMALLINT字段并传入一个Postgres从整数隐式转换为SMALLINT的值时,我遇到了一个非常类似的问题。我通过明确演员阵容来解决这个问题。由于media_类型是VARCHAR(20)类型,Postgres正在从TEXT类型执行隐式转换。试试这个:


其中media\u type=$1::VARCHAR(20)

在静态、快速的查询中,正在使用项\u media\u type\u索引。 在绑定较慢的查询中,未使用项\媒体\类型\索引

“项目”表中“介质类型”列的选择性是什么?如果您做了以下操作:

SELECT media_type, COUNT(*)
  FROM item
  GROUP BY media_type
  ORDER BY 2 desc
媒体类型是否均衡,或者与其他媒体类型相比,“收藏”媒体类型是否相对较少?如果“Collection”项相对较少,那么我会冒险猜测:对于静态查询,解析器知道您正在查询“Collection”,并且可以确定“Collection”的计数较低,并且索引可能值得使用。但是在bind变量的情况下,解析器不知道您使用的是哪种媒体类型。其他一些媒体类型的值可能占表中记录的很大比例(比如20%)。在这种情况下,扫描比使用索引还要快。解析器需要做出决定,它恰好决定不使用索引(对于您的情况是错误的,但是对于其他媒体类型可能是正确的)。这只是基于其他一些rdbms如何工作的猜测


在这种情况下,如果您知道选择性属性是非常不正确的,那么答案是硬编码,使用动态sql强制延迟解析,或者如果您认为这是正确的,则强制使用索引。

这是PostgreSQL中一个长期存在的问题,历史上需要一些有趣的规划器调整来解决。它在PostgreSQL 9.2(现在是测试版)中得到了修复,不过还是一如既往地感谢Tom Lane

E.1.3.1.3。优化器

提高计划员选择参数化计划(Tom)的能力 车道)

一个准备好的语句现在可以被解析、分析和重写,但不需要 必须有计划。当准备好的计划执行时 参数,规划器可能会为每个常量重新规划它,或者 如果通用计划的成本接近某个公司的成本,则可能会执行该计划 持续的具体计划


请参阅和。有很多关于处理准备好的/参数化的语句的信息,这些语句比上的正常语句运行得慢。

这看起来值得一试——尽管它也在更高效的索引查找计划中进行转换。谢谢!PostgreSQL 9.2是否有预期的发布日期?我运气不好就去找了。另外,postgresqlbetas通常有多稳定?@luis我在开发工作中尽可能运行postgresqlbetas,从来没有遇到过问题。但是,我还没有在生产中使用它们。如果您仍处于开发阶段,那么使用测试版是一件很简单的事情。对于生产-嗯,Pg总体上是令人惊讶的稳定,虽然偶尔会有危险的bug,但由于回归测试,它们通常处于奇怪的情况下。我不能建议您在生产中运行beta测试版-这是出于某种原因的beta测试版,团队认为它还没有准备好-但如果有关键问题,我会这样做。如果可能,请解决问题并等待发布。@luis PostgreSQL 9.2于今天发布,仅供参考。