当前位置: 首页 > news >正文

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 查询和优化技巧&#xff0c;设计的初衷和真正的实现原理是什么。 在 h2database SQL like 查询实现类中&#xff08;CompareLike&#xff09;&#xff0c;可以看到 SQL 语言到具体执行的实现、也可以看到数据库尝试优化语句的过程&#xff0c;以及查询优化…...

wpf中listview内容居中显示

在WPF中使用ListView经常会用到GridView作为视图&#xff0c;但是却碰到GridViewColumn不能居中对齐的问题&#xff0c; 实现方法 给ListViewItem设置Style,让ListViewItem在水平方向拉伸填充&#xff1a; <Setter Property"HorizontalContentAlignment" Value&…...

第二章 C++的输出

系列文章目录 第一章 C的输入 文章目录 系列文章目录前言一、个人名片二、cout三、printf总结 前言 今天来学C的输出吧&#xff01; 一、个人名片 二、cout cout 三、printf printf 总结 最近懒得写博客怎么办&#xff1f;...

Qt中常用容器组控件介绍和实操

目录 常用容器组控件(Containers)&#xff1a; 1.Group Box 2.Scroll Area 3.Tab Widget 4.Frame 5.Dock Widget 常用容器组控件(Containers)&#xff1a; 控件名称依次解释如下(常用的用红色标出&#xff09;: Group Box: 组合框: 提供带有标题的组合框框架Scroll Area…...

kafka、rabbitmq 、rocketmq的区别

一、语言不同 RabbitMQ是由内在高并发的erlanng语言开发&#xff0c;用在实时的对可靠性要求比较高的消息传递上。 kafka是采用Scala语言开发&#xff0c;它主要用于处理活跃的流式数据,大数据量的数据处理上 RocketMQ是采用java语言开发的 二、吞吐量 kafka吞吐量更高&…...

java的amazonaws接口出现无法执行http请求:管道中断

java使用amazonaws的接口上传文件到minio出现以下异常&#xff1a; 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 项目时&#xff0c;以下命令是关键的。 第一行是用于配置项目&#xff0c;而第二行用于构建项目。 Visual Studio 15 2017 Visual Studio 16 2019 Visual Studio 17 2022 在CMake中&#xff0c;DCMAKE_BUILD_TYPE是用于指定项目的构建…...

将 mysql 数据迁移到 clickhouse (最新版)

一、前驱知识 已经在mysql中插入了海量的数据了&#xff0c;这个时候mysql 承载不了这么大的数据&#xff0c;并且数据只需要查询&#xff0c;修改和删除非常少&#xff0c;并且不需要支持事务&#xff0c;这个时候需要换一个底层存储&#xff0c;这里选用的是 clickhouse 来进…...

LeetCode 69.x的平方

LeetCode 69.x的平方 思路&#xff1a; 二分查找。从1到x进行二分查找&#xff0c;每次判断mid的平方是否<x&#xff0c; 如果是&#xff0c;则更新ansmid&#xff0c;并缩小区间&#xff1b; 如果不是&#xff0c;则缩小区间&#xff1b; 最后则找到最接近的ans&#xff0…...

【小白入门】ASP.NET Core 创建 Web API

ASP.NET Core 支持使用 C# 创建 RESTful 服务&#xff0c;也称为 Web API。 若要处理请求&#xff0c;Web API 使用控制器。 Web API 中的 控制器 是派生自 ControllerBase 的类。 本文介绍了如何使用控制器处理 Web API 请求。 Web API 包含一个或多个派生自 ControllerBase …...

如何使用摩尔信使MThings连接网络设备

帽子&#xff1a; 摩尔信使MThings支持Modbus-TCP、Modbus-RTU Over TCP、Modbus-TCP Over UDP、Modbus-RTU Over UDP。 TCP链接中&#xff0c;摩尔信使MThings支持灵活的连接方式&#xff0c;主机可作为客户端也可以作为服务端&#xff0c;同时支持模拟从机以客户端方式向远…...

2023自动驾驶 车道线检测数据集

目录 2023自动驾驶 车道线检测关键数据集 下载链接 labelme标注制作数据: 车道线分割项目记录-tusimple数据集处理 2023自动驾驶 车道线检测关键数据集 下载链接 2023自动驾驶 车道线检测关键数据集 下载链接_Xiaobai_Zhao的博客-CSDN博客 labelme标注制作数据:...

排序算法-冒泡排序法(BubbleSort)

排序算法-冒泡排序法&#xff08;BubbleSort&#xff09; 1、说明 冒泡排序法又称为交换排序法&#xff0c;是从观察水中的气泡变化构思而成的&#xff0c;原理是从第一个元素开始&#xff0c;比较相邻元素的大小&#xff0c;若大小顺序有误&#xff0c;则对调后再进行下一个…...

3d tiles规范boundingVolume属性学习

3d tiles的瓦片&#xff08;Tiles&#xff09;包含一些属性&#xff0c;其中第一项是boundingVolume&#xff1b;下面学习boundingVolume&#xff1b; boundingVolume&#xff0c;这个翻译为边界范围框&#xff0c;如果直译为边界体积可能有问题&#xff0c;其实就是包围盒的意…...

【开题报告】如何借助chatgpt完成毕业论文开题报告

步骤 1&#xff1a;确定论文主题和研究问题 首先&#xff0c;你需要确定你的论文主题和研究问题。这可以是与软件开发、算法、人工智能等相关的任何主题。确保主题具有一定的研究性和可行性。 步骤 2&#xff1a;收集相关文献和资料 在开始撰写开题报告之前&#xff0c;收集相…...

微信小程序通过 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中有些超时设置&#xff0c;本文汇总了nginx中几个超时设置 Nginx 中的超时设置包括&#xff1a; “client_body_timeout”&#xff1a;设置客户端向服务器发送请求体的超时时间&#xff0c;单位为秒。 “client_header_timeout”&#xff1a;设置客户端向服务器发送请…...

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# 题解 一、题目 编写函数&#xff0c;实现许多图片编辑软件都支持的「颜色填充」功能。 待填充的图像用二维数组 image 表示&#xff0c;元素为初始颜色值。初始坐标点的行坐标为 sr 列坐标为 sc。需要填充的新颜色为 newColor。 「周围区域」是指颜色相…...

内排序算法

排序算法是面试中常见的问题&#xff0c;不同算法的时间复杂度、稳定性和适用场景各不相同。按照数据量和存储方式可以将排序算法分为 内排序&#xff08;Internal Sorting&#xff09;和 外排序&#xff08;External Sorting&#xff09;。 内排序是指对所有待排序的数据都可…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...