Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

PostgreSQL source code interpretation (33)-query statement # 18 (query optimization-expression preprocessing # 3)

2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

< num_subclauses) { reference = subclauses; num_subclauses = nclauses; } } else//单个约束条件或者带有表达式的约束条件,如(X1 AND X2) OR X3等 { reference = list_make1(clause); break; } } /* * Just in case, eliminate any duplicates in the reference 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. */ 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// is this predicate equivalent to a single conditional expression? {if (! equal (refclause, clause)) {win = false; break } if (win) / / found the common predicate winners = lappend (winners, refclause); / / added to the result} / * * If no winners, we can't transform the OR * / if (winners = = NIL) return make_orclause (orlist) / / if found, return / * * Generate new OR list consisting of the remaining sub-clauses as is. * * found and generated new conditions * * 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. * / neworlist = NIL; foreach (temp, orlist) / / traversing the OR linked list {Expr * clause = (Expr *) lfirst (temp); if (and_clause ((Node *) clause)) / / AND statement {List * subclauses = ((BoolExpr *) clause)-> args;// gets the conditional statement parameter subclauses = list_difference (subclauses, winners) / / remove the same part if (subclauses! = NIL) / / successfully, and generate a new AND statement {if (list_length (subclauses) = = 1) neworlist = lappend (neworlist, linitial (subclauses)); else neworlist = lappend (neworlist, make_andclause (subclauses)) } else {neworlist = NIL; / * degenerate case, see above * / break }} else// is not an AND statement {if (! list_member (winners, clause)) / / a single conditional statement, directly add conditional neworlist = lappend (neworlist, clause); else// OR statement? The public part has proposed to return directly without adding other conditions / / according to the absorption law, X AND (X OR B) is equivalent to X {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) / / newly generated linked list {if (list_length (neworlist) = = 1) winners = lappend (winners, linitial (neworlist)); else winners = lappend (winners, make_orclause (pull_ors (neworlist); / / flattening OR} / * * And return the constructed AND clause, again being wary of a single * element and AND/OR flatness. * / / return result if (list_length (winners) = = 1) return (Expr *) linitial (winners); else return make_andclause (pull_ands (winners)); / / flattening AND}

Pull_ors

/ * * pull_ors * Recursively flatten nested OR clauses into a single or-clause list. * * Input is the arglist of an OR clause. * Returns the rebuilt arglist (note original list structure is not touched). * / static List * pull_ors (List * orlist) {List * out_list = NIL; ListCell * arg; foreach (arg, orlist) {Node * subexpr = (Node *) lfirst (arg); / * Note: we can destructively concat the subexpression's arglist * because we know the recursive invocation of pull_ors will have * built a new arglist not shared with any other expr. Otherwise we'd * need a list_copy here. * / if (or_clause (subexpr)) out_list = list_concat (out_list, pull_ors (BoolExpr *) subexpr)-> args)); / / Recursive flattening else out_list = lappend (out_list, subexpr);} return out_list;}

Pull_ands

/ * * pull_ands * Recursively flatten nested AND clauses into a single and-clause list. * * Input is the arglist of an AND clause. * Returns the rebuilt arglist (note original list structure is not touched). * / static List * pull_ands (List * andlist) {List * out_list = NIL; ListCell * arg; foreach (arg, andlist) {Node * subexpr = (Node *) lfirst (arg); / * Note: we can destructively concat the subexpression's arglist * because we know the recursive invocation of pull_ands will have * built a new arglist not shared with any other expr. Otherwise we'd * need a list_copy here. * / if (and_clause (subexpr)) out_list = list_concat (out_list, pull_ands (BoolExpr *) subexpr)-> args)); / / Recursive flattening else out_list = lappend (out_list, subexpr);} return out_list;} IV. Tracking analysis

Test script:

Select * from t_dwxx where (FALSE OR dwbh = '1001') AND ((dwbh =' 1001' AND dwbh = '1002') OR (dwbh =' 1001' AND dwbh = '1003'))

This statement is normalized to the following SQL statement:

Select * from t_dwxx where dwbh=' 1001' AND (dwbh='1002' OR dwbh='1003');-- execution plan testdb=# explain verbose select * from t_dwxx where (FALSE OR dwbh=' 1001') AND ((dwbh=' 1001' AND dwbh='1002') OR (dwbh=' 1001' AND dwbh='1003')) QUERY PLAN -Seq Scan on public.t_dwxx (cost=0.00..12.80 rows=1 width=474) Output: dwmc Dwbh, dwdz Filter: ((t_dwxx.dwbh):: text = '1001'::text) AND (t_dwxx.dwbh):: text =' 1002'::text) OR ((t_dwxx.dwbh):: text = '1003'::text) (3 rows)

Gdb tracking:

(gdb) b find_duplicate_orsBreakpoint 1 at 0x7811b4: file prepqual.c, line 418. (gdb) cContinuing.Breakpoint 1, find_duplicate_ors (qual=0x2727528, is_check=false) at prepqual.c:418418 if (or_clause ((Node *) qual)) # input parameters, the BoolExpr#args linked list has two elements, one is (FALSE OR dwbh = '1001') # the other is ((dwbh = '1001' AND dwbh =' 1002') OR (dwbh = '1001' AND dwbh =' 1003')) (gdb) p * (BoolExpr *) qual$2 = {xpr = {type = T_BoolExpr}, boolop = AND_EXPR, args = 0x2726c88, location =-1} (gdb) p * ((BoolExpr *) qual)-> args$3 = {type = T_List, length = 2, head = 0x2726c68 Tail = 0x2727508}... # enter AND branch 462else if (and_clause ((Node *) qual)). # get the first element of the linked list 470 Expr * arg = (Expr *) lfirst (temp) # re-entering find_duplicate_ors#FALSE OR dwbh='1001' has previously been simplified to dwbh='1001', so return Breakpoint 1, find_duplicate_ors (qual=0x2726bc8, is_check=false) at prepqual.c:418418 if (or_clause ((Node *) qual)) (gdb) n462 else if (and_clause ((Node *) qual)) (gdb) # 515 return qual directly here (gdb) n516} (gdb) 475 if (arg & & IsA (arg, Const))... 497 andlist = lappend (andlist, arg); (gdb) n468 foreach (temp, (BoolExpr *) qual)-> args) (gdb) n470 Expr * arg = (Expr *) lfirst (temp); (gdb) 472 arg = find_duplicate_ors (arg, is_check) The next element of the # linked list, namely # ((dwbh = '1001' AND dwbh =' 1002') OR (dwbh = '1001' AND dwbh =' 1003')) # consists of two BoolExpr (gdb) p * (BoolExpr *) arg$23 = {xpr = {type = T_BoolExpr}, boolop = OR_EXPR, args = 0x27270d8, location =-1} (gdb) p * ((BoolExpr *) arg)-> args$24 = {type = T_List, length = 2, head = 0x27270b8 Tail = 0x27274b8} (gdb) p * (Node *) ((BoolExpr *) arg)-> args- > head- > data.ptr_value$25 = {type = T_BoolExpr} (gdb) p * (Node *) ((BoolExpr *) arg)-> args- > head- > next- > data.ptr_value$26 = {type = T_BoolExpr}.. # arg on the left and right sides of args is finished with 424 foreach (temp, ((BoolExpr *) qual)-> args) (gdb) 457 orlist = pull_ors (orlist) ... # enter process_duplicate_ors460 return process_duplicate_ors (orlist); (gdb) stepprocess_duplicate_ors (orlist=0x2727858) at prepqual.c:529529 List * reference = NIL;...# to get the linked list of the least predicates (gdb) p * reference$36 = {type = T_List, length = 2, head = 0x27278a8, tail = 0x27278f8}. # get the common predicate winner! That is, dwbh = '1001' (gdb) p * winners$40 = {type = T_List, length = 1, head = 0x2727918, tail = 0x2727918}... (gdb) canonicalize_qual (qual=0x2727528, is_check=false) at prepqual.c:309309 return newqual; (gdb) p * newqual$43 = {type = T_BoolExpr} (gdb) p * (BoolExpr *) newqual$45 = {xpr = {type = T_BoolExpr}, boolop = AND_EXPR, args = 0x2727c18, location =-1} # DONE! 5. Summary

1. The mathematical basis of optimization: Boolean algebra and related laws.

2. The process of expression normalization: the processing logic of expression flattening and common predicate extraction.

VI. Reference materials

Boolean algebra

Prepqual.c

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report