mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-15 02:46:59 +08:00
Until now PostgreSQL has not been very smart about optimizing away IS NOT NULL base quals on columns defined as NOT NULL. The evaluation of these needless quals adds overhead. Ordinarily, anyone who came complaining about that would likely just have been told to not include the qual in their query if it's not required. However, a recent bug report indicates this might not always be possible. Bug 17540 highlighted that when we optimize Min/Max aggregates the IS NOT NULL qual that the planner adds to make the rewritten plan ignore NULLs can cause issues with poor index choice. That particular case demonstrated that other quals, especially ones where no statistics are available to allow the planner a chance at estimating an approximate selectivity for can result in poor index choice due to cheap startup paths being prefered with LIMIT 1. Here we take generic approach to fixing this by having the planner check for NOT NULL columns and just have the planner remove these quals (when they're not needed) for all queries, not just when optimizing Min/Max aggregates. Additionally, here we also detect IS NULL quals on a NOT NULL column and transform that into a gating qual so that we don't have to perform the scan at all. This also works for join relations when the Var is not nullable by any outer join. This also helps with the self-join removal work as it must replace strict join quals with IS NOT NULL quals to ensure equivalence with the original query. Author: David Rowley, Richard Guo, Andy Fan Reviewed-by: Richard Guo, David Rowley Discussion: https://postgr.es/m/CAApHDvqg6XZDhYRPz0zgOcevSMo0d3vxA9DvHrZtKfqO30WTnw@mail.gmail.com Discussion: https://postgr.es/m/17540-7aa1855ad5ec18b4%40postgresql.org
130 lines
4.9 KiB
C
130 lines
4.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* planmain.h
|
|
* prototypes for various files in optimizer/plan
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/optimizer/planmain.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef PLANMAIN_H
|
|
#define PLANMAIN_H
|
|
|
|
#include "nodes/pathnodes.h"
|
|
#include "nodes/plannodes.h"
|
|
|
|
/* GUC parameters */
|
|
#define DEFAULT_CURSOR_TUPLE_FRACTION 0.1
|
|
extern PGDLLIMPORT double cursor_tuple_fraction;
|
|
extern PGDLLIMPORT bool enable_self_join_removal;
|
|
|
|
/* query_planner callback to compute query_pathkeys */
|
|
typedef void (*query_pathkeys_callback) (PlannerInfo *root, void *extra);
|
|
|
|
/*
|
|
* prototypes for plan/planmain.c
|
|
*/
|
|
extern RelOptInfo *query_planner(PlannerInfo *root,
|
|
query_pathkeys_callback qp_callback, void *qp_extra);
|
|
|
|
/*
|
|
* prototypes for plan/planagg.c
|
|
*/
|
|
extern void preprocess_minmax_aggregates(PlannerInfo *root);
|
|
|
|
/*
|
|
* prototypes for plan/createplan.c
|
|
*/
|
|
extern Plan *create_plan(PlannerInfo *root, Path *best_path);
|
|
extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
|
|
Index scanrelid, List *fdw_exprs, List *fdw_private,
|
|
List *fdw_scan_tlist, List *fdw_recheck_quals,
|
|
Plan *outer_plan);
|
|
extern Plan *change_plan_targetlist(Plan *subplan, List *tlist,
|
|
bool tlist_parallel_safe);
|
|
extern Plan *materialize_finished_plan(Plan *subplan);
|
|
extern bool is_projection_capable_path(Path *path);
|
|
extern bool is_projection_capable_plan(Plan *plan);
|
|
|
|
/* External use of these functions is deprecated: */
|
|
extern Sort *make_sort_from_sortclauses(List *sortcls, Plan *lefttree);
|
|
extern Agg *make_agg(List *tlist, List *qual,
|
|
AggStrategy aggstrategy, AggSplit aggsplit,
|
|
int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations,
|
|
List *groupingSets, List *chain, double dNumGroups,
|
|
Size transitionSpace, Plan *lefttree);
|
|
extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
|
LimitOption limitOption, int uniqNumCols,
|
|
AttrNumber *uniqColIdx, Oid *uniqOperators,
|
|
Oid *uniqCollations);
|
|
|
|
/*
|
|
* prototypes for plan/initsplan.c
|
|
*/
|
|
extern PGDLLIMPORT int from_collapse_limit;
|
|
extern PGDLLIMPORT int join_collapse_limit;
|
|
|
|
extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode);
|
|
extern void add_other_rels_to_query(PlannerInfo *root);
|
|
extern void build_base_rel_tlists(PlannerInfo *root, List *final_tlist);
|
|
extern void add_vars_to_targetlist(PlannerInfo *root, List *vars,
|
|
Relids where_needed);
|
|
extern void find_lateral_references(PlannerInfo *root);
|
|
extern void create_lateral_join_info(PlannerInfo *root);
|
|
extern List *deconstruct_jointree(PlannerInfo *root);
|
|
extern bool restriction_is_always_true(PlannerInfo *root,
|
|
RestrictInfo *restrictinfo);
|
|
extern bool restriction_is_always_false(PlannerInfo *root,
|
|
RestrictInfo *restrictinfo);
|
|
extern void distribute_restrictinfo_to_rels(PlannerInfo *root,
|
|
RestrictInfo *restrictinfo);
|
|
extern RestrictInfo *process_implied_equality(PlannerInfo *root,
|
|
Oid opno,
|
|
Oid collation,
|
|
Expr *item1,
|
|
Expr *item2,
|
|
Relids qualscope,
|
|
Index security_level,
|
|
bool both_const);
|
|
extern RestrictInfo *build_implied_join_equality(PlannerInfo *root,
|
|
Oid opno,
|
|
Oid collation,
|
|
Expr *item1,
|
|
Expr *item2,
|
|
Relids qualscope,
|
|
Index security_level);
|
|
extern void match_foreign_keys_to_quals(PlannerInfo *root);
|
|
|
|
/*
|
|
* prototypes for plan/analyzejoins.c
|
|
*/
|
|
extern List *remove_useless_joins(PlannerInfo *root, List *joinlist);
|
|
extern void reduce_unique_semijoins(PlannerInfo *root);
|
|
extern bool query_supports_distinctness(Query *query);
|
|
extern bool query_is_distinct_for(Query *query, List *colnos, List *opids);
|
|
extern bool innerrel_is_unique(PlannerInfo *root,
|
|
Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel,
|
|
JoinType jointype, List *restrictlist, bool force_cache);
|
|
extern bool innerrel_is_unique_ext(PlannerInfo *root, Relids joinrelids,
|
|
Relids outerrelids, RelOptInfo *innerrel,
|
|
JoinType jointype, List *restrictlist,
|
|
bool force_cache, List **uclauses);
|
|
extern List *remove_useless_self_joins(PlannerInfo *root, List *jointree);
|
|
|
|
/*
|
|
* prototypes for plan/setrefs.c
|
|
*/
|
|
extern Plan *set_plan_references(PlannerInfo *root, Plan *plan);
|
|
extern bool trivial_subqueryscan(SubqueryScan *plan);
|
|
extern Param *find_minmax_agg_replacement_param(PlannerInfo *root,
|
|
Aggref *aggref);
|
|
extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid);
|
|
extern void record_plan_type_dependency(PlannerInfo *root, Oid typid);
|
|
extern bool extract_query_dependencies_walker(Node *node, PlannerInfo *context);
|
|
|
|
#endif /* PLANMAIN_H */
|