Postgres在使用date()函数时不使用索引

时间:2014-12-15 21:17:26

标签: sql database postgresql indexing database-optimization

我的架构是

CREATE TABLE a (
  id     BIGINT PRIMARY KEY,
  dt     TIMESTAMP NOT NULL
);

我在dt上创建了一个索引:

CREATE INDEX a_dt_index ON a (dt);

当我使用像

这样的查询时,索引工作正常
SELECT *
FROM a
WHERE dt >= '2008-12-30' AND dt < '2008-12-31';

但是当我使用date()函数时,索引没有被使用。

SELECT *
FROM a
WHERE date(dt) = '2008-12-30'

在我看来,这两个查询在语义上是相同的,那么为什么不使用索引呢? 为什么我必须创建一个明确的date()索引?

CREATE INDEX a_date_index ON a (date(dt));

2 个答案:

答案 0 :(得分:5)

您可以阅读以下链接,详细了解indexes and date。但TL; DR

  

函数是数据库的黑盒子。

因此

  

如果在where子句中使用任何函数,则需要使用该函数创建显式索引。数据库不理解您的语义等效性。

类似于

的情况
 WHERE UPPER(NAME)

不在NAME列中使用索引。根据数据库UPPER功能与BLACKBOX没有区别。替换它。

 WHERE BLACKBOX(NAME)

答案 1 :(得分:1)

查看使用日期函数的示例输出

postgres# select id, date(dt), dt from a;
 id |    date    |             dt             
----+------------+----------------------------
  1 | 2014-12-15 | 2014-12-15 16:32:13.942183
  2 | 2014-12-15 | 2014-12-15 16:34:05.480178
(2 rows)

Time: 2.190 ms

存储的数据类型不同。

其他人可能会以不同的方式使用该功能:

postgres#  SELECT *
FROM a
WHERE dt >= '2014-12-15 16:33' AND dt < '2014-12-16 ';
 id |             dt             
----+----------------------------
  2 | 2014-12-15 16:34:05.480178
(1 row)

Time: 2.168 ms
postgres#  SELECT *
FROM a
WHERE date(dt) >= '2014-12-15 16:33' AND dt < '2014-12-16 ';
 id |             dt             
----+----------------------------
  1 | 2014-12-15 16:32:13.942183
  2 | 2014-12-15 16:34:05.480178
(2 rows)

我没有在docs中找到这个功能!!但这里是描述:

postgres# \df+ date()
                                                                                   List of functions
Schema   | Name | Result data type |     Argument data types     |  Type  | Security | Volatility |  Owner   | Language |   Source code    |               Description                
------------+------+------------------+-----------------------------+--------+----------+------------+----------+----------+------------------+------------------------------------------
 pg_catalog | date | date             | abstime                     | normal | invoker  | stable     | postgres | internal | abstime_date     | convert abstime to date
 pg_catalog | date | date             | timestamp without time zone | normal | invoker  | immutable  | postgres | internal | timestamp_date   | convert timestamp to date
 pg_catalog | date | date             | timestamp with time zone    | normal | invoker  | stable     | postgres | internal | timestamptz_date | convert timestamp with time zone to date
(3 rows)