Insight h2database 执行计划评估以及 Selectivity
生成执行计划是任何一个数据库不可缺少的过程。通过本文看执行计划生成原理。
最优的执行计划就是寻找最小计算成本的过程。
本文侧重 BTree 索引的成本计算的实现 以及 基础概念选择度的分析。
寻找最优执行计划
找到最佳的索引,实现最少的遍历,得到想要的结果
单表查询情况
/*** 根据查询条件,获取最佳执行计划.** @param masks per-column comparison bit masks, null means 'always false',* see constants in IndexCondition* @return the plan item* @see org.h2.table.Table#getBestPlanItem*/
public PlanItem getBestPlanItem(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {// 以扫描索引作为执行计划的默认索引PlanItem item = new PlanItem();item.setIndex(getScanIndex(session));// 表的近似行数 * 10 作为默认成本,最差情况的 Cost 。// long cost = 10 * (tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET);item.cost = item.getIndex().getCost(session, null, null, null);// 获取 table 包含的所有索引ArrayList<Index> indexes = getIndexes();if (indexes != null && masks != null) {// 跳过扫描索引(上述的 ScanIndex )for (int i = 1, size = indexes.size(); i < size; i++) {Index index = indexes.get(i);// 计算当前索引的成本, 不同的索引有不同的成本计算公式。double cost = index.getCost(session, masks, filter, sortOrder);// 记录/更新最小成本的索引,以此作为最佳执行计划if (cost < item.cost) {item.cost = cost;item.setIndex(index);}}}return item;
}
多表查询情况
/*** 使用穷举策略寻找最佳执行计划* 前提:少于 7 个表关联的情况下。 关联表太多的情况下,会采用随机 + 贪心算法,得出次优的执行计划* @see org.h2.command.dml.Optimizer#calculateBestPlan*/
private void calculateBruteForceAll() {TableFilter[] list = new TableFilter[filters.length];// 关联表(filters) 排列组合 穷举策略,试算各种组合执行计划的成本Permutations<TableFilter> p = Permutations.create(filters, list);// 如果组合遍历次数超过 127 次((x & 127) == 0),或者寻找的耗时超过 cost 的10倍,证明优化过程本末倒置,则停止这个过程。for (int x = 0; !canStop(x) && p.next(); x++) {testPlan(list);}
}
BTree 索引的成本计算
/*** 计算 B-tree 索引中搜索数据所需的预估成本。* Calculate the cost for the given mask as if this index was a typical* b-tree range index. This is the estimated cost required to search one* row, and then iterate over the given number of rows.** @param masks the search mask. condition.getMask(indexConditions), 根据查询条件确定是哪种比较(EQUALITY、RANGE、START、END)* @param rowCount the number of rows in the index, 数据总行数* @see org.h2.index.BaseIndex#getCostRangeIndex*/
protected long getCostRangeIndex(int[] masks, long rowCount, TableFilter filter, SortOrder sortOrder) {rowCount += Constants.COST_ROW_OFFSET;long cost = rowCount;long rows = rowCount;// 总选择度,针对联合索引的情况,计算各个 column 综合参数int totalSelectivity = 0;// 没有查询条件的情况,预估成本是 rowCount, 等于全表扫描if (masks == null) {return cost;}// 遍历索引的 columns, 做两件事:查询条件是否匹配索引列,匹配的成本计算for (int i = 0, len = columns.length; i < len; i++) {Column column = columns[i];int index = column.getColumnId();int mask = masks[index];if ((mask & IndexCondition.EQUALITY) == IndexCondition.EQUALITY) {// 等值比较情况下,如果是 unique 索引,cost 相比以下是最小的。if (i == columns.length - 1 && getIndexType().isUnique()) {cost = 3;break;}// 动态计算总选择度,查询条件与索引 column 重合度越高,选择越大// 为了便于理解,公式还可以改写为:totalSelectivity = totalSelectivity + (100 - totalSelectivity) * column.getSelectivity() / 100;// 也就是:总选择度 = 已有的选择度 + 已有的非选择度中再次用 column 选择度计算的增量totalSelectivity = 100 - ((100 - totalSelectivity) * (100 - column.getSelectivity()) / 100);// 估算当前选择度下的非重复的数据行数(假设索引的选择性是均匀分布的)long distinctRows = rowCount * totalSelectivity / 100;if (distinctRows <= 0) {distinctRows = 1;}// 选择度越大,这里的 rows,也就是 cost 越小。rows = Math.max(rowCount / distinctRows, 1);// cost >= 3cost = 2 + rows;} else if ((mask & IndexCondition.RANGE) == IndexCondition.RANGE) {cost = 2 + rows / 4;break;} else if ((mask & IndexCondition.START) == IndexCondition.START) {cost = 2 + rows / 3;break;} else if ((mask & IndexCondition.END) == IndexCondition.END) {cost = rows / 3;break;} else {// 如果索引的 columns 不支持匹配,则直接终止计算。对于联合索引的情况,如果首列不支持匹配,那么认定此索引失效。break;}}// 当查询中的 ORDER BY 与索引的排序顺序匹配时,// 使用这个索引进行查询通常比使用其他索引更加高效,因此查询优化器会相应地调整这个索引的成本。if (sortOrder != null) {boolean sortOrderMatches = true;int coveringCount = 0;int[] sortTypes = sortOrder.getSortTypes();for (int i = 0, len = sortTypes.length; i < len; i++) {// 匹配计算...coveringCount++;}if (sortOrderMatches) {// 当有两个或更多的覆盖索引可供选择时,查询优化器会倾向于选择覆盖更多列的索引。// 覆盖更多列的索引 cost 更少来体现。cost -= coveringCount;}}return cost;
}
Selectivity
概念
Selectivity is used by the cost based optimizer to calculate the estimated cost of an index.
Selectivity 100 means values are unique, 10 means every distinct value appears 10 times on average.
人工指定 Selectivity
-- sets the selectivity (1-100) for a column.
ALTER TABLE TEST ALTER COLUMN NAME SELECTIVITY 100;
人工更新 Selectivity
-- Updates the selectivity statistics of tables.
ANALYZE SAMPLE_SIZE 1000;
自动更新 Selectivity
随着表数据的更新操作,对应列的 Selectivity 也在发生变化。基于累计值 analyzeAuto 来决定什么时候触发Analysis, 也就是更新 Selectivity。
/*** 默认为 2000 ,也就是说,对表进行大约 2000 次更改后,将对每个用户表运行 ANALYZE。* 自数据库启动以来,每次运行 ANALYZE 的时间间隔都会加倍。* 它不会在本地临时表上运行,也不会在 SELECT 触发器的表上运行。* @see org.h2.engine.DbSettings#analyzeAuto*/
public final int analyzeAuto = get("ANALYZE_AUTO", 2000);
相关文章:
Insight h2database 执行计划评估以及 Selectivity
生成执行计划是任何一个数据库不可缺少的过程。通过本文看执行计划生成原理。 最优的执行计划就是寻找最小计算成本的过程。 本文侧重 BTree 索引的成本计算的实现 以及 基础概念选择度的分析。 寻找最优执行计划 找到最佳的索引,实现最少的遍历,得到想要…...
[天翼杯 2021]esay_eval - RCE(disabled_function绕过||AS_Redis绕过)+反序列化(大小写wakeup绕过)
[天翼杯 2021]esay_eval 1 解题流程1.1 分析1.2 解题1.2.1 一阶段1.2.2 二阶段二、思考总结题目代码: <?php class A{public $code = "";...
基于SSM+Vue的在线作业管理系统的设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用Vue技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
Webapck 解决:[webpack-cli] Error: Cannot find module ‘vue-loader/lib/plugin‘ 的问题
1、问题描述: 其一、报错为: [webpack-cli] Error: Cannot find module vue-loader/lib/plugin 中文为: [webpack-cli] 错误:找不到模块“vue-loader/lib/plugin” 其二、问题描述为: 在项目打包的时候 npm run …...
使用UiPath和AA构建的解决方案 5. 使用UiPath ReFramework处理采购订单
在本章中,我们将使用UiPath Robotic Enterprise Framework(简称ReFramework)创建自动化。ReFramework是一个快速构建强大的UiPath自动化的模板。它可以作为所有UiPath项目的起点。 模板可以满足您在任何自动化中的大部分核心需求——在配置文件中读取和存储数据,强大的异常…...
SQL基本语法用例大全
文章目录 SQL语法概述简单查询计算列查询条件查询范围查询使用逻辑运算符过滤数据使用IN操作符过滤数据格式化结果集模糊查询行数据过滤数据排序数据统计分析分组总计简单子查询多行子查询多表链接插入数据更新和删除数据使用视图数据库管理数据表管理 SQL语法概述 SQL(Struct…...
MAX17058_MAX17059 STM32 iic 驱动设计
本文采用资源下载链接,含完整工程代码 MAX17058-MAX17059STM32iic驱动设计内含有代码、详细设计过程文档,实际项目中使用代码,稳定可靠资源-CSDN文库 简介 MAX17058/MAX17059 IC是微小的锂离子(Li )在手持和便携式设备的电池电量计。MAX170…...
大数据笔记-大数据处理流程
大家对大数据处理流程大体上认识差不多,具体做起来可能细节各不相同,一幅简单的大数据处理流程图如下: 1)数据采集:数据采集是大数据处理的第一步。 数据采集面对的数据来源是多种多样的,包括各种传感器、社…...
wps演示时图片任意位置拖动
wps演示时图片任意位置拖动 1.wps11.1版本,其他版本的宏插件可以自己下载。2.先确认自己的wps版本是不是11.13.检查是否有图像工具4.检查文件格式和安全5.开发工具--图像6.选中图像控件,右击选择查看代码,将原有代码删除,将下边代…...
NodeJs中使用JSONP和Cors实现跨域
跨域是为了解决浏览器请求域名,协议,端口不同的接口,相同的接口是不需要实现跨域的。 1.使用JSONP格式实现跨域 实现步骤 动态创建一个script标签 src指向接口的地址 定义一个函数和后端调用的函数名一样 实现代码 -- 在nodejs中使用http内…...
Typora for Mac:优雅的Markdown文本编辑器,提升你的写作体验
Typora是一款强大的Markdown文本编辑器,专为Mac用户设计。无论你是写作爱好者,还是专业作家或博客作者,Typora都能为你提供无与伦比的写作体验。 1. 直观的界面设计 Typora的界面简洁明了,让你专注于写作,而不是被复…...
STM32使用HAL库驱动TA6932数码管驱动芯片
TA6932介绍 8段16位,支持共阴共阳LED数码管。 2、STM32CUBEMX配置引脚 推挽配置即可。 3、头文件 /******************************************************************************************** * TA6932:8段16位数码管驱动 *******************…...
day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)
目录 浅拷贝 1.拷贝对象①Object.assgin() ②展开运算符newObj {...obj}拷贝对象 2.拷贝数组 ①Array.prototype.concat() ② newArr [...arr] 深拷贝 1.通过递归实现深拷贝 2.lodash/cloneDeep实现 3.通过JSON.stringify()实现 异常处理 throw抛异常 try/catch捕获…...
Python爬虫(二十三)_selenium案例:动态模拟页面点击
本篇主要介绍使用selenium模拟点击下一页,更多内容请参考:Python学习指南 #-*- coding:utf-8 -*-import unittest from selenium import webdriver from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import timeclass douyuSelenium…...
nodejs+vue宠物店管理系统
例如:如何在工作琐碎,记录繁多的情况下将宠物店管理的当前情况反应给管理员决策,等等。在此情况下开发一款宠物店管理系统小程序, 困扰管理层的许多问题当中,宠物店管理也是不敢忽视的一块。但是管理好宠物店又面临很多麻烦需要解决,于是乎变得非常合乎时…...
ceph版本和Ceph的CSI驱动程序
ceph版本和Ceph的CSI驱动程序 ceph查看ceph版本Ceph的CSI驱动程序 ceph ceph版本和Ceph的CSI驱动程序 查看ceph版本 官网ceph-releases-index Ceph的CSI驱动程序 Ceph的CSI驱动程序 https://github.com/ceph/ceph-csi...
Android Studio Flutter真机调试错误
错误:Could not locate aapt. Please ensure you have the Android buildtools installed. No application found for TargetPlatform.android_arm64. Is your project missing an android/app/src/main/AndroidManifest.xml? Consider running "flutter crea…...
MQ - 41 容灾:跨地域、跨可用区的容灾和同步的方案设计
文章目录 导图概述容灾能力的理论基础集群内和集群间容灾RTO 和 RPO集群内容灾方案的原理分析RTO 和 RPO跨集群容灾方案的原理分析三种复制方式客户端连接集群主备切换方式一 直连 Broker方式二 域名方式三 虚拟 IP (推荐)双向同步RTO 和 RPOApache Kafka MirrorMaker (V2版…...
vue3学习(二)--- ref和reactive
文章目录 ref1.1 ref将基础类型和对象类型数据转为响应式1.2 ref()获取id元素1.3 isRef reactive1.1 reactive()将引用类型数据转为响应式数据,基本类型无效1.2 ref和reactive的联系 toRef 和 toRefs1.1 如果原始对象是非响应式的就不会更新视图 数据是会变的 ref …...
网络-HTTPS
文章目录 前言一、HTTPS简介优点SSL/TSL工作流程 加密1、对称加密2、非对称加密 二、使用HTTPS1.openSSL生成私钥(1)node服务端(2)nginx配置https服务(前端) nginx服务 总结 前言 Http 存在不安全、无状态…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
