PostgreSQL数据库分区裁剪——constraint exclusion

这篇具有很好参考价值的文章主要介绍了PostgreSQL数据库分区裁剪——constraint exclusion。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

constraint exclusion约束排除有如下类型:不使用、对所有表使用、对otherrel使用。首先看一下官方解释:Controls the query planner’s use of table constraints to optimize queries. The allowed values of constraint_exclusion are on (examine constraints for all tables), off (never examine constraints), and partition (examine constraints only for inheritance child tables and UNION ALL subqueries). partition is the default setting. It is often used with traditional inheritance trees to improve performance.Currently, constraint exclusion is enabled by default only for cases that are often used to implement table partitioning via inheritance trees. Turning it on for all tables imposes extra planning overhead that is quite noticeable on simple queries, and most often will yield no benefit for simple queries. If you have no tables that are partitioned using traditional inheritance, you might prefer to turn it off entirely. (Note that the equivalent feature for partitioned tables is controlled by a separate parameter, enable_partition_pruning.)

typedef enum{
	CONSTRAINT_EXCLUSION_OFF,	/* do not use c_e */
	CONSTRAINT_EXCLUSION_ON,	/* apply c_e to all rels */
	CONSTRAINT_EXCLUSION_PARTITION	/* apply c_e to otherrels only */
}			ConstraintExclusionType;

控制查询优化器使用表约束以优化查询。constraint_exclusion 的允许值是 on(检查所有表的约束)、off(从不检查约束)和 partition(仅检查继承子表和 UNION ALL 子查询的约束)。partition 是默认设置。它通常与传统的继承树一起使用以提高性能。目前,约束排除通常仅在用于通过继承树实现表分区的情况下默认启用。为所有表打开它会带来额外的计划开销,这在简单查询中非常明显,而且通常不会对简单查询产生任何好处。如果没有使用传统继承式分区表,可能更愿意完全关闭它。(请注意,分区表的等效功能由单独的参数 enable_partition_pruning 控制。)
constraint_exclusion GUC参数仅由relation_excluded_by_constraints(src/backend/optimizer/util/plancat.c文件)使用,该函数检测是否因为表具有自不一致的限制(self-inconsistent restrictions)或与表的适用约束不一致的约束而不需要扫描该表(restrictions inconsistent with the relation’s applicable constraints)。注意:这只检查rel->relid、rel->reloptkind和rel->baserestrictinfo;因此可以在填充RelOptInfo的其他字段之前调用它。Detect whether the relation need not be scanned because it has either self-inconsistent restrictions, or restrictions inconsistent with the relation’s applicable constraints. Note: this examines only rel->relid, rel->reloptkind, and rel->baserestrictinfo; therefore it can be called before filling in other fields of the RelOptInfo.

relation_excluded_by_constraints函数在两处分支中调用:

  1. set_rel_size为base relation设定大小估计时,如果reloptkind为base relation,调用relation_excluded_by_constraints函数来判定该表是否被exclusion
  2. set_append_rel_size为simple append relation设定大小估计时,遍历root->append_rel_list,为列表中的每个RelOptInfo调用relation_excluded_by_constraints函数来判定是否被exclusion

入参:rel->baserestrictinfoSQL关联到relation上的SQL谓词表达式列表
rel->reloptkind是枚举类型(RELOPT_BASEREL, RELOPT_JOINREL, RELOPT_OTHER_MEMBER_REL, RELOPT_OTHER_JOINREL, RELOPT_UPPER_REL, RELOPT_OTHER_UPPER_REL, RELOPT_DEADREL),目前仅在其为RELOPT_BASEREL或RELOPT_OTHER_MEMBER_REL才可执行relation_excluded_by_constraints函数
rel->relid是表的OID(OID of the relation)
流程:首先对SQL是否有关联到relation上的SQL谓词表达式列表和constant-FALSE-or-NULL限制先进行判定,对constraint_exclusion GUC参数进行判定,由此知道appendrel member时,reloptkind为RELOPT_OTHER_MEMBER_REL。在进行下一步之前我们先阅读一下手册的内容Constraint exclusion only works when the query’s where clause contains constants. The planner analyzes the query before values from parameters (in prepared statemetns) or stored procedures are substituted in the query. For the same reason, “stable” functions such as CURRENT_DATE must be avoided, 约束排除仅在查询的 WHERE 子句包含常量时才起作用。在查询中替换来自参数(在预备语句中)或存储过程的值之前,优化器解析查询。因此下面的代码就是从restrictions和constraint列表中剔除任何包含可变函数的表达式。最终调用函数predicate_refuted_by进行判定。文章来源地址https://www.toymoban.com/news/detail-475271.html

bool relation_excluded_by_constraints(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){
	bool		include_noinherit;
	bool		include_notnull;
	bool		include_partition = false;
	ListCell   *lc; List	   *safe_restrictions; List	   *constraint_pred; List	   *safe_constraints;
		
	Assert(IS_SIMPLE_REL(rel)); /* As of now, constraint exclusion works only with simple relations. */	
	if (rel->baserestrictinfo == NIL) return false; /* If there are no base restriction clauses, we have no hope of proving anything below, so fall out quickly. */	
	if (list_length(rel->baserestrictinfo) == 1){ /* Regardless of the setting of constraint_exclusion, detect constant-FALSE-or-NULL restriction clauses.  Because const-folding will reduce "anything AND FALSE" to just "FALSE", any such case should result in exactly one baserestrictinfo entry.  This doesn't fire very often, but it seems cheap enough to be worth doing anyway.  (Without this, we'd miss some optimizations that 9.5 and earlier found via much more roundabout methods.) */
		RestrictInfo *rinfo = (RestrictInfo *) linitial(rel->baserestrictinfo); Expr	   *clause = rinfo->clause;
		if (clause && IsA(clause, Const) && (((Const *) clause)->constisnull || !DatumGetBool(((Const *) clause)->constvalue))) return true;
	}

	/* Skip further tests, depending on constraint_exclusion. */
	switch (constraint_exclusion){
		case CONSTRAINT_EXCLUSION_OFF: /* In 'off' mode, never make any further tests */
			return false;
		case CONSTRAINT_EXCLUSION_PARTITION: /* When constraint_exclusion is set to 'partition' we only handle appendrel members.  Partition pruning has already been applied, so there is no need to consider the rel's partition constraints here. */
			if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL) break;			/* appendrel member, so process it */
			return false;
		case CONSTRAINT_EXCLUSION_ON: /* In 'on' mode, always apply constraint exclusion.  If we are considering a baserel that is a partition (i.e., it was directly named rather than expanded from a parent table), then its partition constraints haven't been considered yet, so include them in the processing here. */
			if (rel->reloptkind == RELOPT_BASEREL) include_partition = true;
			break;				/* always try to exclude */
	}

	/* Check for self-contradictory restriction clauses.  We dare not make deductions with non-immutable functions, but any immutable clauses that are self-contradictory allow us to conclude the scan is unnecessary. Note: strip off RestrictInfo because predicate_refuted_by() isn't expecting to see any in its predicate argument. */
	safe_restrictions = NIL;
	foreach(lc, rel->baserestrictinfo){
		RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
		if (!contain_mutable_functions((Node *) rinfo->clause)) safe_restrictions = lappend(safe_restrictions, rinfo->clause);
	}	
	if (predicate_refuted_by(safe_restrictions, safe_restrictions, true)) return true; /* We can use weak refutation here, since we're comparing restriction clauses with restriction clauses. */

	/* Only plain relations have constraints, so stop here for other rtekinds. */
	if (rte->rtekind != RTE_RELATION)
		return false;

	/* If we are scanning just this table, we can use NO INHERIT constraints, but not if we're scanning its children too.  (Note that partitioned tables should never have NO INHERIT constraints; but it's not necessary for us to assume that here.) */
	include_noinherit = !rte->inh;
	/* Currently, attnotnull constraints must be treated as NO INHERIT unless this is a partitioned table.  In future we might track their inheritance status more accurately, allowing this to be refined. */
	include_notnull = (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE);
	/* Fetch the appropriate set of constraint expressions. */
	constraint_pred = get_relation_constraints(root, rte->relid, rel, include_noinherit, include_notnull, include_partition);
	/* We do not currently enforce that CHECK constraints contain only immutable functions, so it's necessary to check here. We daren't draw conclusions from plan-time evaluation of non-immutable functions. Since they're ANDed, we can just ignore any mutable constraints in the list, and reason about the rest. */
	safe_constraints = NIL;
	foreach(lc, constraint_pred){
		Node	   *pred = (Node *) lfirst(lc);
		if (!contain_mutable_functions(pred)) safe_constraints = lappend(safe_constraints, pred);
	}

	/* The constraints are effectively ANDed together, so we can just try to
	 * refute the entire collection at once.  This may allow us to make proofs
	 * that would fail if we took them individually.
	 * Note: we use rel->baserestrictinfo, not safe_restrictions as might seem
	 * an obvious optimization.  Some of the clauses might be OR clauses that
	 * have volatile and nonvolatile subclauses, and it's OK to make
	 * deductions with the nonvolatile parts.
	 * We need strong refutation because we have to prove that the constraints
	 * would yield false, not just NULL.
	 */
	if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
		return true;
	return false;
}

到了这里,关于PostgreSQL数据库分区裁剪——constraint exclusion的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PostgreSQL Linux操作PostgreSQL数据库

    PostgreSQL教程 菜鸟教程:https://www.runoob.com/postgresql/postgresql-tutorial.html 登录PG数据库:psql -U 用户名(U需要大写) 登录PG数据库(指定主机、端口,并进入指定数据库): psql -U 用户名 -h 127.0.0.1 -p 5432 -d 数据库名 -U 登录的用户名 -h 连接的主机(默认127.0.0.1,可替换成远程主机

    2024年02月11日
    浏览(64)
  • [运维|数据库] docker postgresql数据库环境变量配置

    要配置Docker中的PostgreSQL数据库的环境变量,可以使用以下方法: 使用Docker命令行: 将 用户名 , 密码 , 数据库名 替换为你想要设置的实际值。这将创建一个名为 mypostgres 的容器,并将 PostgreSQL 的用户名、密码和数据库名设置为指定的值。 -p 5432:5432 指定了容器内部和主机之间

    2024年02月09日
    浏览(66)
  • 数据库新闻速递 -- POSTGRESQL 正在蚕食数据库市场 (翻译)

    开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请加 liuaustin3微信号 ,在新加的朋友会分到3群(共1140人左右 1 + 2 + 3) 尽管NoSQL数据库继续蓬勃发展,但关系型数据库仍

    2024年02月13日
    浏览(63)
  • PostgreSQL-数据库命令

    一个数据库是一个或多个模式的集合,而模式包含表、函数等。因此,完整的逻辑组织结构层次是服务器实例(PostgreSQL Server)、数据库(Database)、模式(Schema)、表(Table),以及某些其他对象(如函数)。一个PostgreSQL服务器实例可以管理多个数据库。当应用程序连接到一

    2024年02月14日
    浏览(53)
  • Postgresql数据库死锁

    ERROR: deadlock detected DETAIL: Process 95 waits for ShareLock on transaction 3553457; blocked by process 187. Process 187 waits for ShareLock on transaction 3553458; blocked by process 95. HINT: See server log for query details. CONTEXT: while updating tuple (0,6) in relation “deadlock_example” 其中 Process 95 在等待共享锁(ShareLock)的事务

    2024年01月20日
    浏览(67)
  • PostgreSQL 创建数据库

    PostgreSQL 创建数据库可以用以下三种方式: CREATE DATABASE 命令需要在 PostgreSQL 命令窗口来执行,语法格式如下: 例如,我们创建一个 runoobdb 的数据库: createdb 命令创建数据库 createdb 是一个 SQL 命令 CREATE DATABASE 的封装。 参数说明: . dbname:要创建的数据库名。 . description:关

    2024年02月12日
    浏览(53)
  • 【PostgreSql】只删除整个数据库的表(不删除数据库)

    环境: windows 数据库: postgresql 前提: 此方法用来删除数据库所有的表,不包括保存的函数语句、查询语句等(可适用于需要删除整个数据库的数据却又不想删除数据库或者数据库正在连接无法被删除的情况) 查询数据库所有的表(假设表都在public模式下) 这个语句会列出

    2024年04月12日
    浏览(58)
  • PostgreSQL连接指定数据库

    要连接到PostgreSQL中的指定数据库,您需要使用以下格式的连接字符串: 其中,username是连接PostgreSQL的用户名,password是该用户的密码,hostname是PostgreSQL服务器的主机名或IP地址,port是PostgreSQL服务器的端口号,database_name是要连接的数据库名称。 例如,如果您要连接到名为my

    2024年02月11日
    浏览(50)
  • postgresql 数据库 索引 介绍

    大家在学习数据库的时候,是不是常常听到索引?那什么是索引呢?索引有哪些作用呢?索引有哪些种类呢?为什么要建索引呢?带着这些疑问,本文带你一起学习postgresql数据库的索引。 索引是提高数据库性能的常用途径。比起没有索引,使用索引可以让数据库服务器更快

    2024年02月13日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包