1

我在相关部分的数据库模式是有一个名为 User 的表,它有一个布尔字段 Admin。此字段 Admin 上有一个索引。

前一天我将完整的生产数据库恢复到我的开发机器上,然后只对数据库进行了非常小的更改,所以它们应该非常相似。

当我在我的开发机器上运行以下命令时,我得到了预期的结果:

EXPLAIN SELECT * FROM user WHERE admin IS TRUE;

Index Scan using index_user_on_admin on user (cost=0.00..9.14 rows=165 width=3658)
Index Cond: (admin = true)
Filter: (admin IS TRUE)

但是,当我在生产机器上运行完全相同的命令时,我得到了这个:

Seq Scan on user  (cost=0.00..620794.93 rows=4966489 width=3871)
Filter: (admin IS TRUE)

因此,它没有使用与查询完美匹配的精确索引,而是使用了近 500 万行的顺序扫描!

然后我尝试运行EXPLAIN ANALYZE SELECT * FROM user WHERE admin IS TRUE;,希望ANALYZE能让 Postgres 意识到顺序扫描 500 万行不如使用索引好,但这并没有改变任何东西。

我还尝试运行REINDEX INDEX index_user_on_admin以防索引损坏,但没有任何好处。

最后,我打了电话VACUUM ANALYZE user,很快就解决了问题。

我对真空的主要理解是它用于回收浪费的空间。可能发生了什么会导致我的索引行为不端如此糟糕,为什么真空修复它?

4

4 回答 4

5
  1. ANALYZE通过更新计划器使用的数据统计信息来确定运行查询的最佳方式,这很可能是有帮助的。VACUUM ANALYZE只需按顺序运行这两个命令,VACUUM第一,ANALYZE第二,但ANALYZE它本身可能就足以提供帮助。

  2. ANALYZE选项与命令EXPLAIN完全无关ANALYZE。它只是导致 Postgres 运行查询并报告实际运行时间,以便可以将它们与规划器预测进行比较(EXPLAIN没有ANALYZE只显示查询计划和规划器认为它将花费多少,但实际上并不运行查询) . 所以EXPLAIN ANALYZE没有帮助,因为它没有更新统计数据。ANALYZE并且EXPLAIN ANALYZE是两个完全不同的动作,只是碰巧使用了同一个词。

于 2012-09-01T22:02:59.157 回答
2

PostgreSQL 保留了许多关于表条件、索引条件、数据等的高级统计信息……这有时会不同步。运行VACUUM将纠正问题。

当您在开发时从头开始重新加载表时,可能会产生相同的效果。

看看这个:

http://www.postgresql.org/docs/current/static/maintenance.html#VACUUM-FOR-STATISTICS

于 2012-09-01T20:33:39.923 回答
1

对于您的问题,部分索引似乎是一个很好的解决方案:

CREATE INDEX admin_users_ix ON users (admin)
    WHERE admin IS TRUE;;

在同一字段上索引大量元组是没有意义的。

于 2012-09-01T22:30:44.403 回答
1

这是我认为最有可能的解释。

您的索引仅在返回非常少量的行时才有用(顺便说一句,我不喜欢索引 bools 出于这个原因 - 您可以考虑使用部分索引,或者甚至添加一个 where admin is true ,因为这将仅将索引保留在无论如何可能可用的情况下)。

如果要检索超过 iirc 表中 10% 的页面,则规划器可能会选择大量的顺序磁盘 I/O 而不是少量的随机磁盘 I/O,因为那样你不会'不必等待盘片转动。寻道速度是一个大问题,PostgreSQL 将倾向于尝试平衡从关系中检索的实际数据量。

您收集的统计数据表明该表要么比它小,要么作为用户的一部分管理员比您拥有的多,因此规划者使用了错误的信息来做出决定。

VACUUM ANALYZE 做了三件事。首先,它冻结对所有事务可见的元组,以便事务回绕不是问题。然后它将对没有事务可见的元组分配为可用空间。这些都没有影响您的问题。然而第三个是它分析表格并收集表格的统计信息。请记住,这是随机抽样,因此有时可能会关闭。我的猜测是,上一次运行时,它抓取了有很多管理员的页面,因此严重高估了系统管理员的数量。

这可能是仔细检查您的 autovacuum 设置的好时机,因为其他地方的统计数据也可能非常过时,但这还远不能确定。特别是,基于成本的真空设置具有默认设置,有时会导致真空无法完全赶上。

于 2012-09-02T02:04:24.523 回答