PostgreSQL代码分析,查询优化部分,canonicalize_qual,postgresql
这里把规范谓词表达式的部分就整理完了,阅读的顺序如下:
一、PostgreSQL代码分析,查询优化部分,canonicalize_qual
二、PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()
三、 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 time when it would try to
* force the expression into canonical AND-of-ORs or OR-of-ANDs form.
* Eventually, we recognized that that had more theoretical purity than
* actual usefulness, and so now the transformation doesn't involve any
* notion of reaching a canonical form.
*
* NOTE: we assume the input has already been through eval_const_expressions
* and therefore possesses AND/OR flatness. Formerly this function included
* its own flattening logic, but that requires a useless extra pass over the
* tree.
*
* Returns the modified qualification.
*/
/*
* 对WHERE语句或ON语句中的条件进行规范化,从集合的角度对AND和OR两个操作做合并分解。
*/
Expr *
canonicalize_qual(Expr *qual)
{
Expr *newqual;
/* Quick exit for empty qual */
if (qual == NULL)
return NULL;
/*
* Pull up redundant subclauses in OR-of-AND trees. We do this only
* within the top-level AND/OR structure; there's no point in looking
* deeper.
*/
/*
* 查找重复的OR操作,即化简条件语句。
* 假设WHERE条件为:
* (A=1 AND B=1) OR (A=1 AND C=1)
* 可以化简为:
* A=1 AND (B=1 OR C=1)
*
* 另外,这个函数中做了将树状的AND或OR语句平面化(flatten,或拉平)的工作,
* 这两个工作主要体现在pull_ands()和pull_ors()两个函数中。
*/
newqual = find_duplicate_ors(qual);
return newqual;
}
/*
* find_duplicate_ors
* Given a qualification tree with the NOTs pushed down, search for
* OR clauses to which the inverse OR distributive law might apply.
* Only the top-level AND/OR structure is searched.
*
* Returns the modified qualification. AND/OR flatness is preserved.
*/
static Expr *
find_duplicate_ors(Expr *qual)
{
/*
* “分支一:or_clause”
*
* 如果WHERE表达式中的主操作是OR,例如是如下形式:
* A=1 OR B=1 OR (C=1 AND D=1)
* 那么参数qual指针实际指向一个BoolExpr结构体。
typedef struct BoolExpr
{
Expr xpr; = 略
BoolExprType boolop; = OR_EXPR,即对下面的3个进行OR操作
List *args; = 3个,分别是A=1和 B=1和(C=1 AND D=1)
} BoolExpr;
*
* 这里的args是一个list,其中的3个元素的类型分别如下:
* 第一个是比较操作,类型是OpExpr
* 第二个是比较操作,类型是OpExpr
* 第三个是AND操作,是一个AND_EXPR类型的BoolExpr,递归调用时会处理
*
* 张大明白的blog:http://blog.csdn.net/shujiezhang
*/
if (or_clause((Node *) qual))
{
List *orlist = NIL;
ListCell *temp;
/* Recurse */
/*
* 对BoolExpr中的三个条件分别进行递归处理。
* 在这里需要重点关注上例中的AND_EXPR类型的BoolExpr,因为在递归调用中,他将
* 触发下一个分支(分支二)。
*/
foreach(temp, ((BoolExpr *) qual)->args)
orlist = lappend(orlist, find_duplicate_ors(lfirst(temp)));
/*
* Don't need pull_ors() since this routine will never introduce an OR
* where there wasn't one before.***这个原因没理解。***
*/
/* 详情见《PostgreSQL代码分析,查询优化部分,process_duplicate_ors》博文*/
return process_duplicate_ors(orlist);
}
/*
* “分支二:and_clause”
*
* 这里主要做了两个操作:
* 1) 如果子语句中有OR类型的子语句,则递归调用find_duplicate_ors,因为 子OR语句中
* 或许也能提取公共项。
* 2) 对AND操作进行拉平。
*/
else if (and_clause((Node *) qual))
{
List *andlist = NIL;
ListCell *temp;
/* Recurse */
/*
* 子语句中存在一系列OR的情况。
* 例如对于:
* A=1 AND ((B=1 AND C=1) OR (B=1 AND D=1))
* 这里的qual指针指向一个AND_EXPR类型的BoolExpr结构体,则
*
typedef struct BoolExpr
{
Expr xpr; = 略
BoolExprType boolop; = AND_EXPR,即对下面的2个进行AND操作
List *args; = 2个,分别是“A=1”和 “((B=1 AND C=1) OR (B=1 AND D=1))”
} BoolExpr;
*
* 对于其中的“((B=1 AND C=1) OR (B=1 AND D=1))”,在递归调用中,
* 会进入“分支一:or_clause”,进而转换为:
* B=1 AND (C=1 OR D=1)
*
* 张大明白的blog:http://blog.csdn.net/shujiezhang
*/
foreach(temp, ((BoolExpr *) qual)->args)
andlist = lappend(andlist, find_duplicate_ors(lfirst(temp)));
/* Flatten any ANDs introduced just below here */
/*
* 拉平。
*
* 因为主语句是AND类型,子语句也是AND类型,所以可以直接把子语句拉到父节点。
*
*/
andlist = pull_ands(andlist);
/* The AND list can't get shorter, so result is always an AND */
return make_andclause(andlist);
}
else
return qual;
}PostgreSQL代码分析,查询优化部分。
张大明白的blog:http://blog.csdn.net/shujiezhang
相关博文:PostgreSQL代码分析,查询优化部分,process_duplicate_ors
更新第一条数据的时候
1+1 = 2
该列上 2 已经存在,所以 update 会出错。
一次 update 有唯一性限制的列的多条记录,可不能这样干。
下面演示下:一 方法一:通过 pg_user 视图查询--1.1 设置用户的 log_statement 参数 postgres=# alter role francs set log_statement="all";ALTER ROLE --1.2 验证 postgres=# select * From pg_user where usename='francs';-[ RECORD 1 ]--------------------usename | francsusesysid | 24920usecreatedb | fusesuper | fusecatupd | fuserepl | fpasswd | ********valuntil | useconfig | {log_statement=all}--1.3 设置用户的 maintenance_work_mem 参数 postgres=# alter role francs set maintenance_work_mem="1GB";ALTER ROLE--1.4 再次验证 postgres=# select * From pg_user where usename='francs';-[ RECORD 1 ]---------------------------------------------usename | francsusesysid | 24920usecreatedb | fusesuper | fusecatupd | fuserepl | fpasswd | ********valuntil | useconfig | {log_statement=all,maintenance_work_mem=1GB} 备注:上面是通过 pg_user.useconfig 查询。二 方法二: 通过 pg_db_role_setting catalog 基表查询--2.1 pg_db_role_setting 表结构 Table "pg_catalog.pg_db_role_setting" Column | Type | Modifiers -------------+--------+----------- setdatabase | oid | not null setrole | oid | not null setconfig | text[] | Indexes: "pg_db_role_setting_databaseid_rol_index" UNIQUE, btree (setdatabase, setrole), tablespace "pg_global"备注:可见 pg_db_role_setting 会针对数据库,用户级别进行记录。--2.2 验证 postgres=# select oid,rolname from pg_authid where rolname='francs'; oid | rolname -------+--------- 24920 | francs(1 row)postgres=# select * From pg_db_role_setting where setrole=24920; setdatabase | setrole | setconfig -----------......余下全文>>