当前位置: 首页 > 面试题库 >

使用索引或位图索引扫描在时间戳上进行高效的PostgreSQL查询?

宋高扬
2023-03-14
问题内容

在PostgreSQL中,我在tickets表的日期字段上有一个索引。当我将字段与进行比较时now(),查询效率很高:

# explain analyze select count(1) as count from tickets where updated_at > now();
                                                             QUERY PLAN                                                                  
---------------------------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=90.64..90.66 rows=1 width=0) (actual time=33.238..33.238 rows=1 loops=1)
   ->  Index Scan using tickets_updated_at_idx on tickets  (cost=0.01..90.27 rows=74 width=0) (actual time=0.016..29.318 rows=40250 loops=1)
         Index Cond: (updated_at > now())
Total runtime: 33.271 ms

如果我尝试将其与now()负间隔进行比较,它会下坡并使用位图堆扫描。

# explain analyze select count(1) as count from tickets where updated_at > (now() - '24 hours'::interval);
                                                                  QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=180450.15..180450.17 rows=1 width=0) (actual time=543.898..543.898 rows=1 loops=1)
->  Bitmap Heap Scan on tickets  (cost=21296.43..175963.31 rows=897368 width=0) (actual time=251.700..457.916 rows=924373 loops=1)
     Recheck Cond: (updated_at > (now() - '24:00:00'::interval))
     ->  Bitmap Index Scan on tickets_updated_at_idx  (cost=0.00..20847.74 rows=897368 width=0)     (actual time=238.799..238.799 rows=924699 loops=1)
           Index Cond: (updated_at > (now() - '24:00:00'::interval))
Total runtime: 543.952 ms

有没有一种更有效的使用日期算术查询的方法?


问题答案:

第一个查询希望找到 rows=74 ,但实际上找到rows=40250
第二个查询期望找到 rows=897368 并实际找到rows=924699

当然,处理23倍的行会花费更多的时间。因此,您的实际时间不足为奇。

的数据统计信息updated_at > now()已过时。跑:

ANALYZE tickets;

并重复您的查询。而您是否认真地拥有数据updated_at > now()呢?听起来不对。

但是,对于最近更改的数据而言,统计数据已过时也就不足为奇了。这是合乎逻辑的。如果查询依赖于当前统计信息,则必须先运行,ANALYZE然后再运行查询。

还要进行测试(仅在您的会话中):

SET enable_bitmapscan = off;

并重复第二次查询以查看没有位图索引扫描的时间。

为什么位图索引扫描更多行?

普通 索引扫描 按索引中的顺序从堆中获取行。这很简单,愚蠢而且没有开销。几行速度很快,但与行数不断增加的位图索引扫描相比,最终成本可能更高。

一个 位图索引扫描
从索引中收集行之前查表。如果同一数据页上有多个行,则可以节省重复访问的时间,并且可以使处理速度大大提高。行越多,机会越大,位图索引扫描将节省时间。

对于更多的行(大约占表的5%,很大程度上取决于实际数据),计划器将切换到表的 顺序扫描 ,并且根本不使用索引。

最佳的选择是Postgres 9.2引入的
仅索引扫描
。只有满足一些前提条件才有可能。如果所有相关列都包含在索引中,则索引类型支持该索引,并且可见性映射表指示数据页上的所有行对所有事务可见,而不必从堆(表)中获取该页,并且索引中的信息就足够了。

该决定取决于您的统计信息(Postgres希望找到多少行及其分布)以及成本设置,最重要的是random_page_costcpu_index_tuple_costeffective_cache_size



 类似资料:
  • 问题内容: 我必须索引包含“时间”字段的文档,该字段的值是一个整数,表示自纪元以来的秒数(又称为Unix时间戳)。 我一直在阅读ES文档,发现了这一点: http://www.elasticsearch.org/guide/reference/mapping/date- format.html 但是似乎如果我要提交unix时间戳并将其存储在“日期”字段中(整数字段对我没有用),我只有两个选择: 实

  • 问题:我有一个SQL Server表,有一个varchar列和数百万行,它被索引。在SQL Server查询工具中运行查询很快,因为它使用索引。当我从JavaJDBCPreparedStatement运行查询时,需要花费很多分钟,调查显示SQLServer会进行表扫描。如何解决此问题?

  • 问题内容: PostgreSQL 9.4 我正好遇到称为节点,并提到所谓的底层位图数据结构的概念,在这个岗位。据我所知,不支持创建位图索引。 问题: 因此,每当需要使用位图数据结构来执行时,我们需要首先构建它,或者PostgreSQL在构建索引期间创建它,并在表发生变化时重新构建它吗? 问题答案: 页面位图是为每个查询动态创建的。它不会被缓存或重复使用,并在位图索引扫描结束时被丢弃。 事先创建页面

  • 问题内容: 我想使用Postgres 9.4 在json列上创建一个索引,该索引将在搜索列中的特定键时使用。 例如,我有一个带有json列“ animals”的“农场”表。 animals列具有通用格式的json对象: 我已经尝试了多个索引(分别): 我想运行如下查询: 并让该查询使用索引。 当我运行此查询时: 那么(1)索引就可以了,但是我无法获得任何索引来解决不平等问题。 这样的索引可能吗?

  • 问题内容: 据我所知,堆表是没有聚簇索引并且没有物理顺序的表。我有一个具有12万行的堆表“扫描”,并且正在使用以下选择: 如果为“ id”列创建非聚集索引,则将获得 223次物理读取 。如果删除非聚集索引并更改表以使“ id”成为主键(以及聚集索引),则将获得 515次物理读取 。 如果聚集索引表如下图所示: 为什么聚簇索引扫描的工作方式类似于表扫描?(或者在检索所有行的情况下更糟)。为什么不使用

  • 问题内容: 我知道索引在内部是B树或类似的树结构。假设索引是为3列构建的,我希望Postgres执行以下操作: 在该B树中找到键[a = 10,b = 20,c = 30], 扫描下10个条目并返回它们。 如果索引只有一列,则解决方案显而易见: 但是,如果有更多的列,解决方案将变得更加复杂。对于2列: 3栏: 请注意查询: 是 不正确的 ,因为它将例如过滤掉[a = 11,b = 10,c = 1