predicate_refuted_by 和 make_new_qual_list的运行逻辑以及PARAM 无法选出一个节点的原因

make_new_qual_list需要使用表达式和分区信息构造新的表达式,但是PARAM不是常量,所以无法构造, 所以predicate_refuted_by判定变大时和约束的时候无法正确的选择节点,动态语句只要使用到分区键都不行

node_count = 2
                              Table "public.bmsql_new_order"
 Column  |  Type   | Nullable | Storage |
---------+---------+----------+---------+
 no_w_id | integer | not null | plain   | 
 no_d_id | integer | not null | plain   | 
 no_o_id | integer | not null | plain   | 
Indexes:
    "bmsql_new_order_pkey" PRIMARY KEY, btree (no_w_id, no_d_id, no_o_id)
Foreign-key constraints:
    "no_order_fkey" FOREIGN KEY (no_w_id, no_d_id, no_o_id) REFERENCES bmsql_oorder(o_w_id, o_d_id, o_id)
DISTRIBUTE BY HASH(no_w_id) TO NODE(dn1, dn2)
Access method: heap


数据分布
benchmarksql=# execute direct on (dn1) 'select distinct no_w_id from public.bmsql_new_order';
 no_w_id 
---------
       1
       5
       2
(3 rows)

benchmarksql=# execute direct on (dn2) 'select distinct no_w_id from public.bmsql_new_order';
 no_w_id 
---------
       4
       3
(2 rows)

语句select no_o_id from bmsql_new_order where no_w_id = 4 and no_d_id = 1 order by no_o_id asc;


========================================

(no_w_id = 4 and no_d_id = 1)
COALESCE(hash_combin_mod(2, hash(no_w_id)), 0) = 1 and (no_d_id = 1)

hash(no_w_id) % node_count = hash(4) % node_count

===============

(no_w_id, no_d_id, no_o_id) is not null 
XC_NODE_ID is not null
ABLE.XC_NODE_ID=id
COALESCE(hash_combin_mod(2, hash(no_w_id)) 0) = 0

第一轮,检测条件
- 限制条件为
1. 主键不为NULL
2. 节点XC_NODE_ID不为null
3. XC_NODE_ID=loc_info.nodeid
4. hash(no_w_id) % node_count = 0

- 输入表达式为
1. (no_w_id = 4 and no_d_id = 1)
2. (hash(no_w_id) % node_count = 1) and no_d_id = 1 (语句条件根据分布方式计算的hash)

由于hash出来判断的节点不一致,所以无法通过判断



=============================================


(no_w_id, no_d_id, no_o_id) is not null 
XC_NODE_ID is not null
XC_NODE_ID=id
COALESCE(hash_combin_mod(2, hash(no_w_id)), 0) = 1


(no_w_id = 4 and no_d_id = 1)
COALESCE(hash_combin_mod(2, hash(no_w_id)), 0) = 1 and (no_d_id = 1)

第而轮,检测条件
- 限制条件为
1. 主键不为NULL
2. 节点XC_NODE_ID不为null
3. XC_NODE_ID=loc_info.nodeid
4. hash(no_w_id) % node_count = 1

- 输入表达式为
1. (no_w_id = 4 and no_d_id = 1)
2. (hash(no_w_id) % node_count = 1) and no_d_id = 1 (语句条件根据分布方式计算的hash)


判定表达式是否可以通过约束的检查

判定通过

// 递归地检查子句clause_list中的子句是否驳斥给定的predicate_list(也就是说,证明它为 false)。


/*
predicate_list
* no_w_id is not null
* no_d_id is not null
* no_o_id is not null
* XC_NODE_ID is not null
* XC_NODE_ID = nodeid
* hash(no_w_id) % node_count = 0

clause_list
* no_w_id = 4
* no_d_id = 1
* hash(no_w_id) % node_count = 1
* no_d_id = 1
*/

/*

predicate_list
* no_w_id is not null
* no_d_id is not null
* no_o_id is not null
* XC_NODE_ID is not null
* XC_NODE_ID = nodeid
* hash(no_w_id) % node_count = 0



clause_list
* no_w_id = $1
* no_d_id = $2
*/

predicate_refuted_by(*predicate_list, *clause_list) {

  predicate_refuted_by_recurse() {
    pclass = predicate_classify(predicate, &pred_info);

    // 拆解表达式,最终不能拆解的表达书为atom
    switch (predicate_classify(clause, &clause_info)) {
      case CLASS_AND:
        switch (pclass) {
          case CLASS_AND: 
            iterate_begin(pitem, predicate, pred_info) {
              if (predicate_refuted_by_recurse(clause, pitem, weak)) {
                result = true;
                break;
              }
            }
            iterate_begin(citem, clause, clause_info) {
              if (predicate_refuted_by_recurse(citem, predicate, weak)) {
                result = true;
                break;
              }
            }
          case CLASS_OR:
          case CLASS_ATOM:
            not_arg = extract_not_arg(predicate);
            if (not_arg && predicate_implied_by_recurse(clause, not_arg, false))
              return true;
            iterate_begin(citem, clause, clause_info) {
              if (predicate_refuted_by_recurse(citem, predicate, weak)) {
                result = true;
                break;
              }
            }
        }
        break;
        .....
        case CLASS_ATOM: {
          .....
          case CLASS_ATOM:
            // 使用此方法判断最终的atom表达式
            return predicate_refuted_by_simple_clause((Expr *) predicate, clause, weak) {
              // 
              if (predicate && IsA(predicate, NullTest) && ((NullTest *) predicate)->nulltesttype == IS_NULL) {
                // 判断null,argisrow直接false,一个是is not null, 拎一个是is null,则直接true
              }

              // 对简单表达式的判断,简单表达式这里指的是 op(left, right)
              return operator_predicate_proof(predicate, clause, true, weak) {
                // no_w_id is not null 从这里跳出
                if (!is_opclause(predicate))
                  return false;
                pred_opexpr = (OpExpr *) predicate;
                if (list_length(pred_opexpr->args) != 2)
                  return false;
                ....(do same as clause)

                if (pred_opexpr->inputcollid != clause_opexpr->inputcollid)
                  return false;

                if (equal(pred_leftop, clause_leftop)) {
                  if (equal(pred_rightop, clause_rightop)) {
                    return operator_same_subexprs_proof(pred_op, clause_op, refute_it);
                  } else {
                    if (pred_rightop == NULL || !IsA(pred_rightop, Const))
                      return false;
                    pred_const = (Const *) pred_rightop;
                    ....
                    // 下面使用const_v构造一个 (l_const != r_cont)并计算,直接返回计算结果,下面的步骤类似
                    //  使用
                    //    hash(no_w_id) % node_count = 0
                    //  和
                    //    hash(no_w_id) % node_count = 1
                    //   为例。最终执行到这里,const对比不一样,返回false
                  }
                  
                } else if (equal(pred_rightop, clause_rightop)) {

                } else if (equal(pred_leftop, clause_rightop)) {

                } else if (equal(pred_rightop, clause_leftop)) {

                } else {
                  return false;
                }
              }
            }
        }
    }
  }
}
/*
  约束使用分区方式和节点序号构造表达式,查询的where表达式需要判断节点,也需要构造类似的表达式
*/

make_new_qual_list() {
  /*
  * let column=val to (like) hash(column)%remote_count = hash(value)%remote_count to hash(column)%remote_count = new_value
  *   column [not] in (v1,v2) to hash(column)%remote [not] in (new_v1,new_v2)
  */
  // 表达式使用分区信息构造 新的clause,规则如上 
  //  例如 (no_w_id = 4 and no_d_id = 1),使用表的分区信息会对no_w_id = 4构造一个新的表达式,
  //   hash(column)%remote_count = hash(value)%remote_count
  //   hash(no_w_id)%remote_count = hash(4)%remote_count
  //  所以最终的clause构造出来是 (hash(no_w_id) % node_count = 1)
  //  动态参数时,此处无法构造
  mutator_equal_expr() {
    get_var_equal_const(op->args, op->opno, context->relid, context->varattno, &var) == null;
      goto next_mutator_equal_expr_;

  next_mutator_equal_expr_:
	  return expression_tree_mutator(node, mutator_equal_expr, context);
  }
}