关于CockroachDB
CockroachDB 是一个分布式关系型数据库,主要设计目标是可扩展,强一致和高可靠 。CockroachDB 旨在无人为干预情况下,以极短的中断时间容忍磁盘、主机、机架甚至整个数据中心的故障 。 CockroachDB 采用完全去中心化架构,集群中各个节点的地位完全对等,同时所有功能封装在一个二进制文件中,可以做到尽量不依赖配置文件直接部署。
关于Hash Join
所谓 Hash Join 就是在表的 join 时候选择一张表作为 buildSide 表来构造哈希表,另外一张表作为 probeSide 表,然后对 probeSide 表的每一行数据都去这个哈希表中查找是否有匹配的数据(其中 buildSide 表通常是小表,probeSide 表通常是较大的表)。
源码解读
本文解析源码位于cockroach/pkg/sql/opt/xform/coster.go
cockroach/coster.go at master · cockroachdb/cockroach · GitHub
讯享网https://github.com/cockroachdb/cockroach/blob/master/pkg/sql/opt/xform/coster.gocomputeHashJoinCost函数,大致位于779-837行
算子逻辑
Hash Join一般用于连接中,左右表数据量较大并且左表行数明显大于右表。连接过程中 Hash Join 为小表建立 hash table,读取大表的每一行,计算关联列的 hash key,通过 hash map 映射到对应元组。
代价计算涉及常数因子及辅助函数
常数因子
- hugeCost:表示的是通常大于开销模型估计结果的一个代价值,hugeCost=1e100
- cpuCostFactor:从 PostgreSQL 中的 DEFAULT_CPU_TUPLE_COST 借鉴而来,cpuCostFactor=0.01
辅助函数
computeFiltersCost:返回执行过滤器的设置和每行成本。这个函数的调用者应该添加 setupCost,并将 perRowCost 乘以预期要过滤的行数。
setupCost += cpuCostFactor perRowCost += cpuCostFactor
讯享网
此处是为了添加一个基本的 perRowCost, 这样调用者就不需要有自己的每行基本成本
算子开销计算公式及流程
计算公式
Cost = 1.25 * leftRowCount + 1.75 * rightRowCount * cpuCostFactor + filterSetup + rowsProcessed * filterPerRow

其中 1.25 是左边计算 hashkey 的开销,1.75 是建立 hashtable 的开销
具体计算流程
- 首先判断 hint 是否禁止 HashJoin,禁止则返回 hugeCost,否则进入下一 步。
- 得到leftRowCount 和 rightRowCount。
- 读表代价: cost := memo.Cost(1.25*leftRowCount+1.75*rightRowCount) * cpuCostFactor。
- 计算 filter cost。FiltersItem 筛选由包含 Select 或 Join 操作符的行,只有当所有条件都为 true 时,才过滤一行。如果该集合为空,则它永远不会过滤行;func ExtractJoinEqualityColumns 提取连接相等列,返回一对列(一个来自左边,一个来自右边),它们在连接中被约束为相等(并且具有等效类型)。
- eqMap := util.FastIntMap{}定义相等过滤器。FastIntMap 当键和值都很小 时,它更有效,它可以通过值传递。
- 估算重新计算的代价:cost += filterSetup。
- 计算两表连接后最终需要总行数的代价 cost+= memo.Cost(rowsProcessed) * filterPerRow,最后返回 cost 值。
实例测试
一般测试
SQL语句
讯享网SELECT * FROM customer JOIN nation ON (c_nationkey = n_nationkey) ;
表的情况
| Input | Left Table: customer | Left row count= |
| Right Table: nation | Right row count=25 |
实验结果
| 读表代价 | filter cost | 连接后的最终代价 |
| leftRowCount = | filterPerRow = 0.01 | cost+=memo.Cost(rowsProcessed)*filterPerRow |
| rightRowCount = 25 | filterSetup = 0.01 | |
| cost = 1875.4375 | cost =1875.4475 | cost = 3375.4475 |
| Output: cost=3375.4475 | ||
Hash Join、Merge Join、Lookup Join 实验对比:
SQL语句
SELECT * FROM customer JOIN nation ON (c_nationkey = n_nationkey) WHERE c_custkey > ;
表的情况
| Input | Left Table: customer | Left row count= |
| Right Table: nation | Right row count=25 |
实验结果
| Hash Join ComputeCost | Merge Join ComputeCost | Lookup Join ComputeCost |
| cost=1161.2729+0.01+6 0914... = 62075... | cost=1032.0948+0.01+780 99... = 79131... | cost=... |
省略号...指小数点后的值
实验结论
- 表中 Lookup Join ComputeCost 明显远大于 Hash Join 和 Merge Join;
- 算子方法返回 cost:computeHashJoinCost(cost ≈ 1161)> computeMergeJoinCost(cost ≈ 1032),这是因为 Merge Join 在 join 的列无序的情 况下最后计算所得的 ComputeCost 还需要加上 sort 的 cost,使得 Merge Join 的 cost 大于 Hash Join;
- 实际执行计划情况对比:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/91635.html