PostgreSQL范围查询索引

时间:2018-10-30 14:10:40

标签: postgresql query-performance database-indexes

假设我在PostgreSQL中有一个简单的表:

CREATE TABLE bingest.some_data (
      report_date DATE NOT NULL,
      client_id UUID NOT NULL,
      value_1 INT, value_2 INT, value_3 INT,
      value_4 INT, value_5 INT, value_6 INT,
      value_7 INT, value_8 INT, value_9 INT,
      value_10 INT, value_11 INT, value_12 INT,
      value_13 INT, value_14 INT, value_15 INT,
      value_16 INT, value_17 INT, value_18 INT,
      value_19 INT,
PRIMARY KEY (report_date, client_id));

我想在以下查询中使用索引

SELECT * FROM some_data WHERE report_date > '2018-10-30';

对于上述查询, EXPLAIN 命令给了我

Seq Scan on some_data  (cost=0.00..18.12 rows=217 width=96)
    Filter: (report_date > '2018-10-30'::date)
Planning time: 0.061 ms
Execution time: 0.019 ms

当我指定上限和下限时使用索引

SELECT * FROM some_data WHERE report_date > '2018-10-30' AND < '2019-10-30'

对此 EXPLAIN 给出以下输出:

Bitmap Heap Scan on some_data  (cost=4.18..11.30 rows=3 width=96)
    Recheck Cond: ((report_date > '2018-10-30'::date) AND (report_date < '2019-10-30'::date))
        ->  Bitmap Index Scan on some_data_pkey  (cost=0.00..4.18 rows=3 width=0)
                Index Cond: ((report_date > '2018-10-30'::date) AND (report_date < '2019-10-30'::date))
Planning time: 0.072 ms
Execution time: 0.027 ms

我还没有任何数据,但我想为此表准备正确的索引。

2 个答案:

答案 0 :(得分:0)

如果表完全为空,则PostgreSQL估计它包含10页(请参见estimate_rel_size中的src/backend/optimizer/util/plancat.c)。

因此,如果一个表包含几行并且尚未自动清空,我们就不会被低估。

结果是,一个空表的估计完全是伪造的,您的观察结果毫无意义。

要测试是否可以使用索引 ,请将enable_seqscan设置为关闭并解释查询。如果它仍然选择昂贵的顺序扫描,则会这样做,因为它无法使用索引。

答案 1 :(得分:0)

如果表为空,则任何有关性能调整的讨论都是理论上的。要真正确定一切,您需要在表中放入很多数据,并使这些数据与可以合理地想到的生产数据集一样真实。

话虽如此,理论上...

表扫描与索引

使用空表时,最有效的执行计划通常是全表扫描。为什么?完整版的启动成本/开销非常低。

索引使用具有高开销(意味着,不管查找到什么内容,仅对其进行搜索的基准成本),但每行成本极低。全表扫描具有极低的开销,且每行成本最高。话虽如此,有两个经验法则:

  • 表越小,索引的用处就越小。
  • 索引搜索的选择性越多,它越有用。搜索索引然后匹配表中90%的行是非常低效的,RDBMS的智能通常足以做到这一点。

估算与统计

根据上述经验法则,RDBMS要确定哪个计划是最有效的,它需要了解数据的一些详细信息,特别是表中的行数以及查询所需要的行数可能会匹配。

我们遇到了catch 22,因为它需要查询数据以找出将返回多少数据,以便它可以选择最有效的查询计划。

因此,所有方法的工作方式就是像Postgres这样的RDBMS存储有关数据的统计信息,以供查询计划者使用。这些统计信息在特定的时间点是准确的,它们是估计值。统计数据示例:

  1. 表的大概行计数
  2. 对于索引,估计每个键的行数
  3. 列中特定值的频率

再次,请记住,这些是估算值。对于Postgres来说,要保证统计数据始终精确无比非常昂贵,但是我们不需要高精度来选择执行计划。 1行表和2行表之间的区别无关紧要。但是1行表与1000行表或100万行表的关系很大。

这里有些不错的读物:https://www.postgresql.org/docs/9.6/static/planner-stats.html

摘要

说了这么多,Postgres可能不太确定表中到底有多少行,但知道它很小。因此,何时使用索引的阈值很高,因此您的第一个查询将进行表扫描。通过第二次日期检查,很可能可以确定查询在检查主键索引时将匹配较少的行数,因此将其用于索引。