Insight h2database SQL like 查询
我们认为的 SQL like 查询和优化技巧,设计的初衷和真正的实现原理是什么。
在 h2database SQL like 查询实现类中(CompareLike),可以看到 SQL 语言到具体执行的实现、也可以看到数据库尝试优化语句的过程,以及查询优化的原理。可以做为条件语句的经典案例去分析。
我们熟知的索引前缀匹配,实现过程和局限可以通过源码体现。
文章中的查询不只局限在 Select 语句,包括 Update、Delete。
SQL like 语句实现
根据之前的文章《Insight H2 database 数据查询核心原理》。 condition 执行的结果返回布尔类型,true or false。
任何表达式都可以是 condition, 根据转换规则,都可以转为布尔类型。
核心方法: org.h2.expression.CompareLike#getValue
/*** 执行 SQL like 表达式,返回 true or false.* 假设 SQL like 语句为 NAME like 'bj%' * @see org.h2.expression.CompareLike#getValue*/
public Value getValue(Session session) {// 从当前行(session)获取对应列(left)的值。 left 对应为:NAME (ExpressionColumn)Value l = left.getValue(session);if (!isInit) {// 获取 like 表达式,正常情况下。 right 对应为:bj% (ValueExpression)Value r = right.getValue(session);String p = r.getString();// 解析 like 表达式,方便后续识别和比对。主要是识别和定位通配符。initPattern(p, getEscapeChar(e));}String value = l.getString();boolean result;if (regexp) {// 正则模式匹配result = patternRegexp.matcher(value).find();} else {// SQL Like 模式匹配。 字符循环比对。result = compareAt(value, 0, 0, value.length(), patternChars, patternTypes);}return ValueBoolean.get(result);
}
SQL like 查询优化
like 查询比较损耗性能,针对特定的情况下,会进行查询优化。
prepare 阶段,重写查询语句,会彻底替换 Condition 对象。
之后,尝试增加索引查询条件,缩小数据遍历的范围。
①查询语句重写
核心方法: org.h2.expression.CompareLike#optimize
在查询准备阶段(org.h2.command.dml.Select#prepare),如果检测到如下的情况,会进行查询语句重写。
if ("%".equals(p)) {// optimization for X LIKE '%': convert to X IS NOT NULLreturn new Comparison(session, Comparison.IS_NOT_NULL, left, null).optimize(session);
}if (isFullMatch()) {// 没有通配符的情况下,约等于等值匹配// optimization for X LIKE 'Hello': convert to X = 'Hello'Value value = ValueString.get(patternString);Expression expr = ValueExpression.get(value);return new Comparison(session, Comparison.EQUAL, left, expr).optimize(session);
}
②增加索引查询条件
尝试限定查找范围 (start or end),而非全表扫描。
比如:select * from city where name like ‘朝阳%’;
等同于:select * from city where name >= ‘朝阳’ and name < ‘朝阴’;
核心方法:org.h2.expression.CompareLike#createIndexConditions
在查询准备阶段(org.h2.command.dml.Select#prepare),如果支持索引前缀匹配,那么就尝试计算匹配范围,增加索引查询条件,达到减少遍历的目的。
/*** like 前缀查询的本质是什么?* 拆解匹配查询字符串,把 like 查询,转为对应规律的字符串范围查询。* 例如:NAME like 'bj%i' --> NAME >= 'bj' && NAME < 'bk'*/
public void createIndexConditions(Session session, TableFilter filter) {// 使用正则模式查询,索引不生效。 NAME REGEXP '^bj.*'if (regexp) {return;}// 非当前表的关联查询语句,索引不生效ExpressionColumn l = (ExpressionColumn) left;if (filter != l.getTableFilter()) {return;}String p = right.getValue(session).getString();initPattern(p, getEscapeChar(e));// 非前缀匹配,索引不生效// private static final int MATCH(char) = 0, ONE(_) = 1, ANY(*) = 2;if (patternLength <= 0 || patternTypes[0] != MATCH) {// can't use an indexreturn;}int dataType = l.getColumn().getType();if (dataType != Value.STRING && dataType != Value.STRING_IGNORECASE && dataType != Value.STRING_FIXED) {// column is not a varchar - can't use the indexreturn;}// 假设查询语句为: NAME like 'bj%i'// 从 patternChars(bj%i) 中提取最佳匹配的前缀字符串 bj。String end;if (begin.length() > 0) {// 增加索引查询查询条件 NAME >= 'bj'。以此作为 like 前缀匹配的起始filter.addIndexCondition(IndexCondition.get(Comparison.BIGGER_EQUAL, l, ValueExpression.get(ValueString.get(begin))));char next = begin.charAt(begin.length() - 1);// search the 'next' unicode character (or at least a character that is higher)// 根据字符串顺序,尝试找到大于前缀的字符串。以此作为 like 前缀匹配的终止for (int i = 1; i < 2000; i++) {end = begin.substring(0, begin.length() - 1) + (char) (next + i);if (compareMode.compareString(begin, end, ignoreCase) == -1) {// 增加索引查询查询条件 NAME < 'bk'。 j 的下一个字符即 k。filter.addIndexCondition(IndexCondition.get(Comparison.SMALLER, l, ValueExpression.get(ValueString.get(end))));break;}}}
}
其他
上述描述的过程,其中有一些细节,需要单独说明。
①通配符模式前缀查找
int maxMatch = 0;
// 存储通配符模式前缀字符串, that is "begin"
StringBuilder buff = new StringBuilder();
// 找到非通配符的前缀字符串。遍历 patternChars , 遇到非精确字符串, 终止。
while (maxMatch < patternLength && patternTypes[maxMatch] == MATCH) {buff.append(patternChars[maxMatch++]);
}
②索引条件校验
createIndexConditions 方式是把所有可以转为范围查找的列都加入了索引条件中(org.h2.table.TableFilter#indexConditions)。
有些列可能并没有索引,所以,需要在准备阶段(org.h2.table.TableFilter#prepare),剔除无效的索引条件。
/*** Prepare reading rows. This method will remove all index conditions that* can not be used, and optimize the conditions.* @see org.h2.table.TableFilter#prepare*/
public void prepare() {// forget all unused index conditions// the indexConditions list may be modified herefor (int i = 0; i < indexConditions.size(); i++) {IndexCondition condition = indexConditions.get(i);if (!condition.isAlwaysFalse()) {Column col = condition.getColumn();if (col.getColumnId() >= 0) {if (index.getColumnIndex(col) < 0) {indexConditions.remove(i);i--;}}}}
}
Code Insight 环境
java -jar h2-1.4.184.jar org.h2.tools.Shell -url "jdbc:h2:~/test;MV_STORE=false" -user sa -password ""
select * from city where name like 'bj%i';SELECT *
FROM INFORMATION_SCHEMA.INDEXES
WHERE TABLE_NAME = 'CITY';
总结
-
SQL like 模式匹配支持正则表达式和通配符两种。
-
常用的通配符模式采用约定的字符串匹配规则确定每一行数据是否符合要求。
-
正则模式匹配不支持优化,需要遍历目标表的每一行,性能损耗大。
-
使用前缀匹配的通配符模式匹配,尝试增加索引列的区间范围条件,优化扫描区间。
-
熟悉条件筛选的底层原理,趋利避害,达到数据查询的最佳性能。
相关文章:
Insight h2database SQL like 查询
我们认为的 SQL like 查询和优化技巧,设计的初衷和真正的实现原理是什么。 在 h2database SQL like 查询实现类中(CompareLike),可以看到 SQL 语言到具体执行的实现、也可以看到数据库尝试优化语句的过程,以及查询优化…...
wpf中listview内容居中显示
在WPF中使用ListView经常会用到GridView作为视图,但是却碰到GridViewColumn不能居中对齐的问题, 实现方法 给ListViewItem设置Style,让ListViewItem在水平方向拉伸填充: <Setter Property"HorizontalContentAlignment" Value&…...
第二章 C++的输出
系列文章目录 第一章 C的输入 文章目录 系列文章目录前言一、个人名片二、cout三、printf总结 前言 今天来学C的输出吧! 一、个人名片 二、cout cout 三、printf printf 总结 最近懒得写博客怎么办?...
Qt中常用容器组控件介绍和实操
目录 常用容器组控件(Containers): 1.Group Box 2.Scroll Area 3.Tab Widget 4.Frame 5.Dock Widget 常用容器组控件(Containers): 控件名称依次解释如下(常用的用红色标出): Group Box: 组合框: 提供带有标题的组合框框架Scroll Area…...
kafka、rabbitmq 、rocketmq的区别
一、语言不同 RabbitMQ是由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上。 kafka是采用Scala语言开发,它主要用于处理活跃的流式数据,大数据量的数据处理上 RocketMQ是采用java语言开发的 二、吞吐量 kafka吞吐量更高&…...
java的amazonaws接口出现无法执行http请求:管道中断
java使用amazonaws的接口上传文件到minio出现以下异常: com.amazonaws.SdkClientException: Unable to execute HTTP request: Broken pipe (Write failed) at com.amazonaws.http.AmazonHttpClient R e q u e s t E x e c u t o r . h a n d l e R e t r y a b l e…...
cmake 多线程编译 指定 Visual Studio 编译器 命令行
当使用CMake来配置和构建一个Visual Studio 项目时,以下命令是关键的。 第一行是用于配置项目,而第二行用于构建项目。 Visual Studio 15 2017 Visual Studio 16 2019 Visual Studio 17 2022 在CMake中,DCMAKE_BUILD_TYPE是用于指定项目的构建…...
将 mysql 数据迁移到 clickhouse (最新版)
一、前驱知识 已经在mysql中插入了海量的数据了,这个时候mysql 承载不了这么大的数据,并且数据只需要查询,修改和删除非常少,并且不需要支持事务,这个时候需要换一个底层存储,这里选用的是 clickhouse 来进…...
LeetCode 69.x的平方
LeetCode 69.x的平方 思路: 二分查找。从1到x进行二分查找,每次判断mid的平方是否<x, 如果是,则更新ansmid,并缩小区间; 如果不是,则缩小区间; 最后则找到最接近的ans࿰…...
【小白入门】ASP.NET Core 创建 Web API
ASP.NET Core 支持使用 C# 创建 RESTful 服务,也称为 Web API。 若要处理请求,Web API 使用控制器。 Web API 中的 控制器 是派生自 ControllerBase 的类。 本文介绍了如何使用控制器处理 Web API 请求。 Web API 包含一个或多个派生自 ControllerBase …...
如何使用摩尔信使MThings连接网络设备
帽子: 摩尔信使MThings支持Modbus-TCP、Modbus-RTU Over TCP、Modbus-TCP Over UDP、Modbus-RTU Over UDP。 TCP链接中,摩尔信使MThings支持灵活的连接方式,主机可作为客户端也可以作为服务端,同时支持模拟从机以客户端方式向远…...
2023自动驾驶 车道线检测数据集
目录 2023自动驾驶 车道线检测关键数据集 下载链接 labelme标注制作数据: 车道线分割项目记录-tusimple数据集处理 2023自动驾驶 车道线检测关键数据集 下载链接 2023自动驾驶 车道线检测关键数据集 下载链接_Xiaobai_Zhao的博客-CSDN博客 labelme标注制作数据:...
排序算法-冒泡排序法(BubbleSort)
排序算法-冒泡排序法(BubbleSort) 1、说明 冒泡排序法又称为交换排序法,是从观察水中的气泡变化构思而成的,原理是从第一个元素开始,比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个…...
3d tiles规范boundingVolume属性学习
3d tiles的瓦片(Tiles)包含一些属性,其中第一项是boundingVolume;下面学习boundingVolume; boundingVolume,这个翻译为边界范围框,如果直译为边界体积可能有问题,其实就是包围盒的意…...
【开题报告】如何借助chatgpt完成毕业论文开题报告
步骤 1:确定论文主题和研究问题 首先,你需要确定你的论文主题和研究问题。这可以是与软件开发、算法、人工智能等相关的任何主题。确保主题具有一定的研究性和可行性。 步骤 2:收集相关文献和资料 在开始撰写开题报告之前,收集相…...
微信小程序通过 movable-area 做一个与vuedraggable相似的上下拖动排序控件
因为只是做个小案例 我就直接代码写page页面里了 其实很简单 组件稍微改一下就好了 wxss /* 设置movable-area的宽度 */ .area{width: 100%; }/* a b c 每条元素的样式 */ movable-view {width: 100%;background-color: red;height: 40px;line-height: 40px;color: #FFFFFF;tex…...
Ceph入门到精通-Nginx超时参数分析设置
nginx中有些超时设置,本文汇总了nginx中几个超时设置 Nginx 中的超时设置包括: “client_body_timeout”:设置客户端向服务器发送请求体的超时时间,单位为秒。 “client_header_timeout”:设置客户端向服务器发送请…...
TCP/IP(十)TCP的连接管理(七)CLOSE_WAIT和TCP保活机制
一 CLOSE_WAIT探究 CLOSE_WAIT 状态出现在被动关闭方,当收到对端FIN以后回复ACK,但是自身没有发送FIN包之前 ① 服务器出现大量 CLOSE_WAIT 状态的原因有哪些? 1、通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态2、但是在一些特殊情况下,就会出现大量连接长…...
LeetCode 面试题 08.10. 颜色填充
文章目录 一、题目二、C# 题解 一、题目 编写函数,实现许多图片编辑软件都支持的「颜色填充」功能。 待填充的图像用二维数组 image 表示,元素为初始颜色值。初始坐标点的行坐标为 sr 列坐标为 sc。需要填充的新颜色为 newColor。 「周围区域」是指颜色相…...
内排序算法
排序算法是面试中常见的问题,不同算法的时间复杂度、稳定性和适用场景各不相同。按照数据量和存储方式可以将排序算法分为 内排序(Internal Sorting)和 外排序(External Sorting)。 内排序是指对所有待排序的数据都可…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
