PostgreSQL代码分析,查询优化部分,process_duplicate_ors

PostgreSQL代码分析,查询优化部分。

/*
 * process_duplicate_ors
 *	  Given a list of exprs which are ORed together, try to apply
 *	  the inverse OR distributive law.
 *
 * Returns the resulting expression (could be an AND clause, an OR
 * clause, or maybe even a single subexpression).
 */

/*
 * 假设我们有四个表,分别是TEST_A,TEST_B,TEST_C,TEST_D,每个表有一列分别是A,B,C,D,
 * 也就是TEST_A有一个A列,TEST_B有一个B列,以此类推。
 *
 * 这个函数处理这种情况,对于一个选择,SELECT * FROM TEST_A,TEST_B,TEST_C,TEST_D
 * WHERE (A=1 AND B=1) OR (A=1 AND C=1) OR (A=1 AND D=1);
 *
 * 语句中的WHERE条件:
 *		(A=1 AND B=1) OR (A=1 AND C=1) OR (A=1 AND D=1)
 * 可以改写为:
 *		(A=1)AND (B=1 OR C=1 OR D=1)
 * 这就是这个函数的主要功能。
 *
 * 这个函数的参数是一个list, 对于上述的WHERE条件,orlist的结构如下:
 * orlist中有一个元素,是OR_EXPR类型的BoolExpr,BoolExpr中的结构如下:
typedef struct BoolExpr
{
	Expr xpr; = 略
	BoolExprType boolop; = OR_EXPR
	List *args;	= OR中的3个条件,即(A=1 AND B=1) OR (A=1 AND C=1) OR (A=1 AND D=1)
	bool plusFlag; = 略
} BoolExpr;
 *
 * 下面分析函数的具体实现,大致的步骤为:
 * 1)分析每个OR中的公共项, 2)提取公共项, 3)合并剩余项为AND。
 */
static Expr *
process_duplicate_ors(List *orlist)
{
	List	   *reference = NIL;
	int			num_subclauses = 0;
	List	   *winners;
	List	   *neworlist;
	ListCell   *temp;

	if (orlist == NIL)
		return NULL;			/* probably can't happen */

	/* 如果只有一个。。。。,那就算了吧 */
	if (list_length(orlist) == 1)		/* single-expression OR (can this
										 * happen?) */
		return linitial(orlist);

	/*
	 * Choose the shortest AND clause as the reference list --- obviously, any
	 * subclause not in this clause isn't in all the clauses. If we find a
	 * clause that's not an AND, we can treat it as a one-element AND clause,
	 * which necessarily wins as shortest.
	 */
	/*
	 * “找最短”。
	 * 在WHERE语句中:
	 *		(A=1 AND B=1) OR (A=1 AND C=1) OR (A=1 AND D=1)
	 * OR操作串联了3个子语句,找到其中最短的一个,因为如果有公共项,那么最短的那个也一定
	 * 包含公共项,那么通过找到最短的那个,在后面的操作里能减少 比较 的次数。
	 * 在上面的WHERE语句中,3个子语句的长度相同,按照如下执行过程,找到的应该是(A=1 AND B=1),
	 * 即第一个。
	 */
	foreach(temp, orlist)
	{
		Expr	   *clause = (Expr *) lfirst(temp);

		if (and_clause((Node *) clause))
		{
			List	   *subclauses = ((BoolExpr *) clause)->args;
			int			nclauses = list_length(subclauses);

			/*
			 * 这里判断子语句里的长度,比如对于(A=1 AND B=1)子语句,
			 * 他实际上是一个AND连接起来的两个 子子语句, 那么他的长度就是2。
			 *
			 * 通过nclauses记录最短的子语句,如果有更短的(nclauses < num_subclauses),
			 * 那么就替换成最短的。
			 */
			if (reference == NIL || nclauses < num_subclauses)
			{
				reference = subclauses;
				num_subclauses = nclauses;
			}
		}
		else
		{
			/*
			 * 还有一种情况, 就是可能子句不是一个AND语句,这样看上去不大符合规则,
			 * 那么把他看做一个整体,那这个就是最短元素。
			 *
			 ******************************
			 * 如果代码执行到这里,那么只有两种情况:
			 * 一种是 ... WHERE (A=1 AND B=1) OR (A=1 AND C=1) OR (A=1)。
			 * 一种是 ... WHERE ((A=1 OR C=1) AND B=1) OR (A=1 OR C=1).
			 * 如果是这两种情况,都可以做如下简化:
			 * 第一种情况简化为 A=1
			 * 第二种情况化简为 (A=1 OR C=1)
			 *
			 * 第三种情况待补充...
			 */
			reference = list_make1(clause);
			break;
		}
	}

	/*
	 * Just in case, eliminate any duplicates in the reference list.
	 */
	/* 找到最短的, 存到List */
	reference = list_union(NIL, reference);

	/*
	 * Check each element of the reference list to see if it's in all the OR
	 * clauses.  Build a new list of winning clauses.
	 */
	/*
	 * “找公共项”。
	 *
	 * NOTE:这时候就能体现“找最短”带来的优势,外层循环次数会少一些。
	 *
	 * 如果WHERE语句是:
	 *		(A=1 AND B=1) OR (A=1 AND C=1) OR (A=1 AND D=1)
	 * “找最短”中找到的一定是(A=1 AND B=1)。
	 * 则外层会有两次循环...(foreach(temp, reference)),两次循环的变量分别为
	 *			A=1 和 B=1。
	 * 内层有三次循环...(foreach(temp2, orlist)),三次循环的变量分别为
	 *			(A=1 AND B=1) 和 (A=1 AND C=1) 和 (A=1 AND D=1)
	 *
	 * 示例如下:
	 * 假如现在外层循环第一次执行,即查找A=1的公共项,进而假如内层循环也是第一次执行,
	 * 即在(A=1 AND B=1)中查找是否存在A=1这个公共项,发现是存在的(list_member),
	 * 则依次判断内层循环的第二个子句...
	 *
	 * 如上例,具体来说,这些循环分别作的操作是:
	 *	外层第一次:
	 *		判断A=1是否在(A=1 AND B=1),在,判断下一个
	 *		判断A=1是否在(A=1 AND C=1),在,判断下一个
	 *		判断A=1是否在(A=1 AND D=1),在,A=1是公共项,记录(winners = lappend...)
	 *	外层第二次:
	 *		判断B=1是否在(A=1 AND B=1),在,判断下一个
	 *		判断B=1是否在(A=1 AND C=1),不在,跳出循环,下一个不用判断了。
	 *		判断B=1是否在(A=1 AND D=1),未执行,因为上一个不含公共项,就不可能提取了。
	 */
	winners = NIL;
	foreach(temp, reference)
	{
		Expr	   *refclause = (Expr *) lfirst(temp);
		bool		win = true;
		ListCell   *temp2;

		foreach(temp2, orlist)
		{
			Expr	   *clause = (Expr *) lfirst(temp2);

			if (and_clause((Node *) clause))
			{
				if (!list_member(((BoolExpr *) clause)->args, refclause))
				{
					win = false;
					break;
				}
			}
			else
			{
				if (!equal(refclause, clause))
				{
					win = false;
					break;
				}
			}
		}

		if (win)
			winners = lappend(winners, refclause);
	}

	/*
	 * If no winners, we can't transform the OR
	 */
	if (winners == NIL)
		return make_orclause(orlist);

	/*
	 * Generate new OR list consisting of the remaining sub-clauses.
	 *
	 * If any clause degenerates to empty, then we have a situation like (A
	 * AND B) OR (A), which can be reduced to just A --- that is, the
	 * additional conditions in other arms of the OR are irrelevant.
	 *
	 * Note that because we use list_difference, any multiple occurrences of a
	 * winning clause in an AND sub-clause will be removed automatically.
	 */
	/*
	 * “提取公共项”。
	 * 用list_difference删除公共项,实现细节不在赘述。
	 */
	neworlist = NIL;
	foreach(temp, orlist)
	{
		Expr	   *clause = (Expr *) lfirst(temp);

		if (and_clause((Node *) clause))
		{
			List	   *subclauses = ((BoolExpr *) clause)->args;

			/* 看这里...看这里..., 消除公共项 */
			subclauses = list_difference(subclauses, winners);
			if (subclauses != NIL)
			{
				/* 消除后,剩余的拼接起来,拼接成:(B=1 OR C=1 OR D=1)*/
				if (list_length(subclauses) == 1)
					neworlist = lappend(neworlist, linitial(subclauses));
				else
					neworlist = lappend(neworlist, make_andclause(subclauses));
			}
			else
			{
				/*
				 * 这说明子语句中,有一个全部是公共项,也就是如下形式:
				 *		... WHERE (A=1 AND B=1) OR (A=1)
				 *
				 * 这时候公共项是A=1,第一个子句是(A=1 AND B=1),第二个子句是(A=1),
				 * 第二个子句经过list_difference,返回的结果是NULL。
				 * 对于这种情况,实际上可以化简为:A=1,因为(A=1 AND B=1)一定满足A=1的情况。
				 */
				neworlist = NIL;	/* degenerate case, see above */
				break;
			}
		}
		else
		{
			if (!list_member(winners, clause))
				neworlist = lappend(neworlist, clause);
			else
			{
				neworlist = NIL;	/* degenerate case, see above */
				break;
			}
		}
	}

	/*
	 * Append reduced OR to the winners list, if it's not degenerate, handling
	 * the special case of one element correctly (can that really happen?).
	 * Also be careful to maintain AND/OR flatness in case we pulled up a
	 * sub-sub-OR-clause.
	 */
	if (neworlist != NIL)
	{
		if (list_length(neworlist) == 1)
			winners = lappend(winners, linitial(neworlist));
		else
			/*neworlist里面应该是(B=1 OR C=1 OR D=1),所以用make_orclause */
			winners = lappend(winners, make_orclause(pull_ors(neworlist)));
	}

	/*
	 * And return the constructed AND clause, again being wary of a single
	 * element and AND/OR flatness.
	 */
	if (list_length(winners) == 1)
		return (Expr *) linitial(winners);
	else
		/* 返回的形式是:(A=1)AND (B=1 OR C=1 OR D=1),所以会用make_andclause */
		return make_andclause(pull_ands(winners));
}
时间: 2024-10-05 21:57:01

PostgreSQL代码分析,查询优化部分,process_duplicate_ors的相关文章

PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()

PostgreSQL代码分析,查询优化部分. 这里把规范谓词表达式的部分就整理完了,阅读的顺序如下: 一.PostgreSQL代码分析,查询优化部分,canonicalize_qual 二.PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors() 三.PostgreSQL代码分析,查询优化部分,process_duplicate_ors ****************************************************************

PostgreSQL代码分析,查询优化部分,canonicalize_qual

PostgreSQL代码分析,查询优化部分. 张大明白的blog:http://blog.csdn.net/shujiezhang 相关博文:PostgreSQL代码分析,查询优化部分,process_duplicate_ors /* * canonicalize_qual * Convert a qualification expression to the most useful form. * * The name of this routine is a holdover from a

静态代码分析工具sonarqube+sonar-runner的安装配置及使用

配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + maven sonarqube + eclipse sonarqube + IDE IntelliJ 使用方式1 :sonarqube + sonar-runner 1.环境 jdk 1.7 sonarqube 4.5.7 (最新的sonarqube都要求jdk1.8,找了一个匹配1.7的较新版本

java代码分析及分析工具

java代码分析及分析工具 一个项目从搭建开始,开发的初期往往思路比较清晰,代码也比较清晰.随着时间的推移,业务越来越复杂.代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰. 作为一个互联网电子商务网站的业务支撑系统,业务复杂不言而喻.从09年开始一直沿用到现在,中间代码经过了多少人的手,留下了多少的坑,已经记不清楚了,谁也说不清了. 代码的维护成本越来越高.代码已经急需做调整和改善.最近项目组专门设立了一个小组,利用业余时间做代码分析的工作,目标对核心代码进行分析并进行设计重构. 代码分析

Java静态代码分析工具Infer

Java静态代码分析工具Infer 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.Infer介绍 Infer是Facebook最新开源的静态程序分析工具,用于在发布移动应用之前对代码进行分析,找出潜在的问题.目前Facebook使用此工具分析Facebook的App,包括Android.iOS.Facebook Messenger和Instagram等. Facebook称该工具帮助其每个月检查出应用潜在的数百个Bug,例如一些空指针访问.资源

$*和[email&#160;protected]之间区别代码分析

#!/bin/bash set 'apple pie' pears peaches for i in $*           /*单引号被去掉,循环单个字符输出*/ do echo $i done [[email protected] Ex_14.02-14.31]# sh 14-14-1 apple pie pears peaches -------------------------------------------------------------- #!/bin/bash set

《linux 内核完全剖析》 keyboard.S 部分代码分析(key_map)

keyboard.S 部分代码分析(key_map) keyboard中间有这么一段,我一开始没看明白,究竟啥意思 key_map: .byte 0,27 .ascii "1234567890-=" .byte 127,9 .ascii "qwertyuiop[]" .byte 13,0 .ascii "asdfghjkl;'" .byte '`,0 .ascii "\\zxcvbnm,./" .byte 0,'*,0,32

20145234黄斐《网络对抗技术》实验四,恶意代码分析

恶意代码 概述 恶意代码是指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的计算机代码.最常见的恶意代码有计算机病毒(简称病毒).特洛伊木马(简称木马).计算机蠕虫(简称蠕虫).后门.逻辑炸弹等. 特征: 恶意的目的,获取靶机权限.用户隐私等 本身是计算机程序,可以执行,并作用于靶机 通过执行发生作用,一般来说不运行是没问题的 恶意代码分析 在大多数情况下,进行恶意代码分析时,我们将只有恶意代码的可执行文件本身,而这些文件并不是我们人类可读的.为了了解这些文件的意义,你需要使用各种工具和技巧

20145326蔡馨熠《网络对抗》——恶意代码分析

20145326蔡馨熠<网络对抗>--恶意代码分析 1.实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所以想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控.. 需要监控什么? 系统中各种程序.文件的行为. 还需要注意是否会出现权限更改的行为. 注册表. 是否有可疑进程. 如果有网络连接的情况,需要注意这个过程中的IP地址与端口. 用什么来监控? 最先想到的肯定是使用wireshark抓包了,再进行进一步分析. Sysinternals