[英]Postgres not using index for date field
我已经创建了索引
CREATE INDEX bill_open_date_idx ON bill USING btree(date(open_date));
和,
Column | Type
open_date | timestamp without time zone
并解释分析如下
情况1
explain analyze select * from bill where open_date >=date('2018-01-01');
Seq Scan on bill (cost=0.00..345264.60 rows=24813 width=1132) (actual time=0.007..1305.730 rows=5908 loops=1)
Filter: (open_date >= '2018-01-01'::date)
Rows Removed by Filter: 3238812
Total runtime: 1306.176 ms
案例2
explain analyze select * from bill where open_date>='2018-01-01';
Seq Scan on bill (cost=0.00..345264.60 rows=24813 width=1132) (actual time=0.006..1220.697 rows=5908 loops=1)
Filter: (open_date>= '2018-01-01 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 3238812
Total runtime: 1221.131 ms
情况3
explain analyze select * from bill where date(open_date) >='2018-01-01';
Index Scan using idx_bill_open_date on bill (cost=0.43..11063.18 rows=22747 width=1132) (actual time=0.016..4.744 rows=5908 loops=1)
Index Cond: (date(open_date) >= '2018-01-01'::date)
Total runtime: 5.236 ms
(3 rows)
我对发生这种情况的原因进行了足够的研究,但是在任何地方都没有适当的解释。 只有第3种情况使用的是我创建的索引,而其他情况没有使用。 为什么会这样呢?
据我了解, 情况2搜索的字符串等效于open_date
列,因此它不使用索引。 但是为什么不选择情况1。另外,如果我错了,请纠正我。
提前致谢!
编辑1:另外,我很高兴知道深入的事情。
以下是要点摘录( https://gist.github.com/cobusc/5875282 )
尽管PostgreSQL将用于创建索引的函数重写为规范形式是很奇怪的,但是当在WHERE子句中使用该函数(以匹配索引函数)时,似乎没有做同样的事情。
不过,我仍然不清楚为什么postgres的开发人员没有想到获取附近的任何匹配索引(或者直到我像情况3那样显式转换date
,我的索引才有用)。 考虑到Postgres是高度发展且可扩展的。
b树索引只能用于搜索条件,前提是该条件如下所示:
<indexed expression> <operator> <expression that is constant during the index scan>
<indexed expression>
必须是您在CREATE INDEX
语句中使用的表达式。
<operator>
必须属于数据类型和索引访问方法的默认运算符类别,或者属于CREATE INDEX
指定的运算符类别。
<expression that is constant during the index scan>
可以为常量,也可以包含IMMUTABLE
或STABLE
函数和运算符,但不包含VOLATILE
。
您的所有查询都满足最后两个条件,但是只有第三个条件满足第一个条件。 这就是为什么只有该查询才能使用索引的原因。
对于覆盖这折磨人的详细资料,请参见注释match_clause_to_indexcol
在postgresql/src/backend/optimizer/path/indxpath.c
:
/*
* match_clause_to_indexcol()
* Determine whether a restriction clause matches a column of an index,
* and if so, build an IndexClause node describing the details.
*
* To match an index normally, an operator clause:
*
* (1) must be in the form (indexkey op const) or (const op indexkey);
* and
* (2) must contain an operator which is in the index's operator family
* for this column; and
* (3) must match the collation of the index, if collation is relevant.
*
* Our definition of "const" is exceedingly liberal: we allow anything that
* doesn't involve a volatile function or a Var of the index's relation.
* In particular, Vars belonging to other relations of the query are
* accepted here, since a clause of that form can be used in a
* parameterized indexscan. It's the responsibility of higher code levels
* to manage restriction and join clauses appropriately.
*
* Note: we do need to check for Vars of the index's relation on the
* "const" side of the clause, since clauses like (a.f1 OP (b.f2 OP a.f3))
* are not processable by a parameterized indexscan on a.f1, whereas
* something like (a.f1 OP (b.f2 OP c.f3)) is.
*
* Presently, the executor can only deal with indexquals that have the
* indexkey on the left, so we can only use clauses that have the indexkey
* on the right if we can commute the clause to put the key on the left.
* We handle that by generating an IndexClause with the correctly-commuted
* opclause as a derived indexqual.
*
* If the index has a collation, the clause must have the same collation.
* For collation-less indexes, we assume it doesn't matter; this is
* necessary for cases like "hstore ? text", wherein hstore's operators
* don't care about collation but the clause will get marked with a
* collation anyway because of the text argument. (This logic is
* embodied in the macro IndexCollMatchesExprColl.)
*
* It is also possible to match RowCompareExpr clauses to indexes (but
* currently, only btree indexes handle this).
*
* It is also possible to match ScalarArrayOpExpr clauses to indexes, when
* the clause is of the form "indexkey op ANY (arrayconst)".
*
* For boolean indexes, it is also possible to match the clause directly
* to the indexkey; or perhaps the clause is (NOT indexkey).
*
* And, last but not least, some operators and functions can be processed
* to derive (typically lossy) indexquals from a clause that isn't in
* itself indexable. If we see that any operand of an OpExpr or FuncExpr
* matches the index key, and the function has a planner support function
* attached to it, we'll invoke the support function to see if such an
* indexqual can be built.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.