首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解PawSQL索引优化算法:让失效的索引重新生效

深入理解PawSQL索引优化算法:让失效的索引重新生效

作者头像
PawSQL
发布于 2025-06-11 05:35:22
发布于 2025-06-11 05:35:22
6200
代码可运行
举报
运行总次数:0
代码可运行

引言

条件中对索引列进行运算导致索引失效是一种常见的性能陷阱。本文深入解读PawSQL的自动优化算法如何针对5种不同的场景,通过智能重写让失效的索引重新生效。

PawSQL优化算法剖析

PawSQL采用了一种逆向思维:既然不能改变索引本身,那就改变查询条件。通过数学等价变换,将作用在索引列上的函数或运算转移到常量一侧,从而让索引重新发挥作用。让我们通过具体场景来理解这个算法的工作原理。

场景一:算术运算优化

考虑这样的查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM orders 
WHERE price +10 > 100;
代码语言:javascript
代码运行次数:0
运行
复制

传统情况下,由于price列参与了运算,索引无法使用。PawSQL的算法会将其重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM orders 
WHERE price > 90;
代码语言:javascript
代码运行次数:0
运行
复制

算法的核心逻辑体现在ValueExpressionCombined的处理中。当检测到形如column + constant > value的表达式时,算法会识别运算符类型(加、减、乘、除),选择相应的逆运算符,将运算转移到常量侧,重构谓词表达式。

这种转换背后的数学原理是等式的基本性质:如果a + b > c,那么a > c - b。

场景二:日期函数优化

考虑这样的查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT*FROM events 
WHERE DATE(create_time)>'2024-01-01';  
代码语言:javascript
代码运行次数:0
运行
复制

传统情况下,DATE()函数包裹索引列会导致索引失效。PawSQL的算法会将其重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * FROM events 
WHERE create_time >'2024-01-01 23:59:59.999999';

算法的核心逻辑体现在DateFunctionRewriter的处理中。当检测到形如DATE(col) op constant的表达式时,算法会识别日期函数类型(DATE(), ADDDATE()等),根据比较运算符(=, >, <等)计算精确时间边界,将函数调用替换为时间范围条件,重构谓词表达式。

这种转换背后的数学原理是:

  • DATE(col) = '2024-01-01' 等价于 col ∈ ['2024-01-01 00:00:00', '2024-01-01 23:59:59.999999']
  • DATE(col) > '2024-01-01' 等价于 col > '2024-01-01 23:59:59.999999'

场景三:类型转换优化

考虑这样的查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM users 
WHERE CAST(age AS VARCHAR)='25'; 

传统情况下,CAST()函数会阻止索引使用。PawSQL的算法会将其重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM users 
WHERE age = 25
代码语言:javascript
代码运行次数:0
运行
复制

算法的核心逻辑体现在CastFunctionRewriter的处理中。算法会检测列上的显式类型转换(CAST(), CONVERT()等),确定源列和目标数据类型,对常量值执行反向类型转换,重构谓词表达式。

这种转换的关键在于保持语义等价性:当目标类型可安全转换时(如字符串转数字),当转换不会导致精度丢失时(如DATETIMEDATE)。

场景四:空值处理优化

考虑这样的查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 SELECT * 
 FROM employees 
 WHERE IFNULL(salary,0)=3000; 

传统情况下,函数包裹列会导致索引失效。PawSQL的算法会将其重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM employees 
WHERE salary =3000;  
代码语言:javascript
代码运行次数:0
运行
复制

算法的核心逻辑体现在NullFunctionRewriter的处理中。算法会识别空值处理函数(IFNULL(), COALESCE()等),提取函数中的默认值参数,根据比较运算符拆解条件:IFNULL(col, default) = constcol = constISNULL(col) = 1col IS NULL,重构谓词表达式。

转换前提:当常量值不等于默认值时,可安全消除函数调用。

场景五:字符串操作优化

考虑这样的查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 SELECT *
 FROM products 
 WHERE SUBSTR(name,1,5)='Apple'; 

传统情况下,SUBSTR()函数会阻止索引使用。PawSQL的算法会将其重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * 
FROM products 
WHERE name LIKE'Apple%'; 
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
算法的核心逻辑体现在StringFunctionRewriter的处理中。算法会识别字符串函数(SUBSTR(), LEFT()等),验证函数参数是否满足索引使用条件:截取起始位置=1,截取长度=常量字符串长度,转换为LIKE前缀匹配表达式,重构谓词表达式。

这种转换的数学基础:LEFT(col, N) = 'abc' 当且仅当 col LIKE 'abc%'LENGTH('abc') = N

算法的技术亮点

1. 递归处理能力

算法能够处理嵌套的复杂表达式。当遇到嵌套函数或多层运算时,它会递归地进行分析和转换,确保每一层都得到正确处理。

2. 运算符方向处理

算法会处理运算符的方向性问题。例如,对于减法和除法这种非交换运算,需要特别考虑操作数的位置:

  • 2 - column > 0 转换为 2 > column
  • column - 2 > 0 转换为 column > 2

3. 比较运算符适配

当涉及负号运算时,算法会相应地调整比较运算符的方向:

  • -column > 5 转换为 column < -5
  • 大于变小于,大于等于变小于等于

4. 上下文的自动化获取

算法的适用条件依赖于列的数据类型、长度、非空约束,PawSQL可以自动化的获取相关信息,做出系统化的优化建议。通过人工的方式查看表结构定义后在进行分析,代价很大,基本上是行不通的。

5. 特殊函数处理

算法针对不同类型的函数采用了专门的处理策略:

  • 时间函数族:ADDDATEDATE_ADDSUBDATE等函数通过函数名替换和参数调整实现优化。
  • 转换函数族:FROM_DAYSTO_DAYSUNIX_TIMESTAMP等函数通过逆函数替换实现优化。
  • 字符串函数:LEFT函数转换为LIKE模式匹配,SUBSTR函数也采用类似策略。
  • ip地址函数:INET_ATON, INET_NTOA在整数和ip地址间相互转换。

实际应用场景举例

  • 用户年龄查询优化

优化前:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-- 查询出生年份,YEAR函数导致索引失效
SELECT * 
FROM users 
WHERE YEAR(birthday)=1990;
代码语言:javascript
代码运行次数:0
运行
复制

优化后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-- 转换为日期范围查询
SELECT * 
FROM users 
WHERE birthday BETWEEN '1990-01-01' AND '1990-12-31';
  • IP地址查询优化

优化前:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-- IP转换函数导致索引失效
SELECT *
FROM access_log 
WHERE INET_ATON(ip_address)=3232235777;

优化后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-- 使用反向转换
SELECT *
FROM access_log 
WHERE ip_address=INET_NTOA(3232235777);

性能提升的量化分析

通过这种优化,查询性能的提升往往是数量级的:

  • 从全表扫描变为索引范围扫描:从O(n)复杂度降低到O(log n)
  • 执行时间:在大表上可能从几秒降低到毫秒级别
  • 资源消耗:显著减少CPU和I/O开销

结语

PawSQL的这个索引优化算法体现了数据库优化领域的一个重要思想:通过智能的SQL重写,在不改变语义的前提下显著提升性能。它不仅解决了开发者经常遇到的索引失效问题,更重要的是,它是自动化的,无需开发者具备深厚的SQL优化经验。

对于数据库开发者而言,理解这类优化算法的原理,不仅能帮助我们更好地使用工具,也能提升我们的SQL编写技能。毕竟,最好的优化,始终是在编写阶段就考虑到索引的使用。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PawSQL 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
gtest单元测试框架介绍及简单使用
Gtest是Google的一个开源框架,它主要用于写单元测试,检查真自己的程序是否符合预期行为。可在多个平台上使用(包括Linux, Mac OS X, Windows, Cygwin和Symbian)。它提供了丰富的断言、致命和非致命失败判断,能进行值参数化测试、类型参数化测试、“死亡测试”。
杨永贞
2022/04/13
4.4K0
gtest单元测试框架介绍及简单使用
纯血鸿蒙APP实战开发——预加载so并读取RawFile文件
本示例主要介绍在TaskPool子线程中使用 dlopen 预加载 so 库并使用句柄调用库函数的方法,以及在Native中使用 pread 系统函数读取Rawfile文件的部分文本内容,并添加 HiLog 日志。
小帅聊鸿蒙
2025/01/21
2960
纯血鸿蒙APP实战开发——预加载so并读取RawFile文件
lycium上面适配OpenHarmony 不同架构的构建
当前lycium上面支持armv7-a和armv8-a的构建,其他架构的构建也是类似的,在HPKBUILD文件中,需要判断架构的地方加上架构相关的信息,这里以新增x86_64架构举例,cmake,makefile, configure构建方式如何修改。
小帅聊鸿蒙
2024/08/28
2210
lycium上面适配OpenHarmony 不同架构的构建
4步成功将三方库——speexdsp移植到OpenHarmony
①在原生库根目录中,存在CMakeLists.txt文件。在原生库下新建build目录通过cmake或者cmake-gui生成makeflie然后make。
小帅聊鸿蒙
2025/04/20
2200
4步成功将三方库——speexdsp移植到OpenHarmony
QT的cmake项目工程配置
QT的项目工程默认使用的是qmake,这本来也没什么问题。但是由于要用到vcpkg这个工具来管理第三方库,好像这个 vcpkg工具只能在cmake的项目中才能使用。
杨永贞
2022/04/13
3.8K0
Android NDK 开发 | CMake 使用手册 - 初见篇
之前写过一篇 《[-NDK 导引篇 -] 在NDK开发之前你应知道的东西》 介绍了在进入 NDK 学习之前,如何摆正自己的角色。时隔两年,NDK 系列文章开始填坑,在上一篇 《 NDK 是什么 | FFmpeg 5.0 编译 so 库》 中,介绍了 NDK 的概念,以及其作用。
张风捷特烈
2022/09/20
1.5K0
Android NDK 开发 | CMake 使用手册 - 初见篇
OpenHarmony开发——CMake方式组织编译的库移植
本文为OpenHarmony开发者提供一些组织编译形式比较常见(CMakeLists、Makefile)的三方库的移植指南,该指南当前仅适用于Hi3516DV300和Hi3518EV300两个平台,文中着重介绍各编译组织方式下工具链的设置方法以及如何将该库的编译添加到OpenHarmony整个工程的构建中。
小帅聊鸿蒙
2024/08/06
5850
OpenHarmony开发——CMake方式组织编译的库移植
HarmonyOS 开发实践 —— 基于lycium的开源c库编译与集成
lycium的使用说明:lycium的特点就是自动化编译,只需要一个./build.sh命令就可以完成编译,下面的编译例子(openssl)代码库是通过hpkbuild脚本从github或者gitee上面拉取,在hpkbuild脚本中已经默认提供了一套编译默认的配置,也可以按照需求修改。
小帅聊鸿蒙
2024/11/23
4030
HarmonyOS 开发实践 —— 基于lycium的开源c库编译与集成
[-NDK 导引篇 -] 在NDK开发之前你应知道的东西
前言 笔者看了一些NDK的项目。一些教程不是HelloWord就是直接整FFmpeg或OpenCV,可谓一个天一个地,而且目录结构和Android3.5的默认结构并不是太一致,一直没找到什么合心的文章。故写此文连接这天地,来总结一下在NDK开发之前你应知道的东西。 ---- 在此之前,先划分三类人,如果不认清自己是什么角色(垃圾)就去玩NDK,你会很糟心: user : 纯粹.so链接库使用者(伸手党) creator : 纯粹ndk开发者,创作.so链接库(创作家) designer : 在现
张风捷特烈
2020/04/30
7790
[-NDK 导引篇 -] 在NDK开发之前你应知道的东西
HarmonyOS 开发实践——对各种图片编解码格式的支持
在lycium目录下会生成usr目录,该目录下存在已编译完成的32位和64位三方库和头文件
小帅聊鸿蒙
2024/11/12
2260
HarmonyOS 开发实践——对各种图片编解码格式的支持
GTest问题_itest.n z
添加以下代码,注意==不要包含gtest/gtest.h头文件==,若多包含可能会出现struct std::__cxx11::basic_stringbuf<_CharT, _Traits, _Alloc>::__xfer_bufptrs' redeclared with different access错误
全栈程序员站长
2022/11/10
7680
C++与lua的结合,LuaBridge的使用
LuaBridge 是一个简单好用的轻量级且无依赖的库,用于在C ++和 LUA(一种强大,快速,轻量级,可嵌入的脚本语言)之间来回映射数据,函数和类。
杨永贞
2022/05/11
1.9K0
C++与lua的结合,LuaBridge的使用
编译Android 使用的 libx264 并使用进行 H.264 编码
在日常的音视频开发中,我们经常使用FFmpeg,因为它确实好用呀,囊括了各种功能!但是有个很严重的问题,如果是编译在Android和IOS上使用,会造成APP的包很大。可以看我编译的FFmpeg在Android上的应用程式。
字节流动
2021/06/09
5K0
编译Android 使用的 libx264 并使用进行 H.264 编码
ArkUI实战开发-NAPI项目
上节笔者简单介绍了使用 DevEco Studio 创建的默认 NAPI 工程结构,本节笔者简单介绍一下 NAPI 工程下 cpp 目录的源码部分。
小帅聊鸿蒙
2024/10/09
1940
ArkUI实战开发-NAPI项目
NDK 是什么 | FFmpeg 5.0 编译 so 库
NDK 全称 Native Development Kit,也就是原生开发工具包 ,官网对它有详细的 中文介绍 。可能一说到 NDK 或 JNI ,大家脑子里第一反应就是集成 C/C++ 。其实 JNI 的含义是 Java Native Interface ,这种接口允许 Java 和其他语言进行交互的,包括但不限于 C/C++ 。目前 Rust 也可以通过 JNI 来和 Java 交互,虽然不太成熟。
张风捷特烈
2022/09/20
1.6K0
NDK 是什么 |  FFmpeg 5.0 编译 so 库
OpenHarmony 内核源码分析(gn应用篇) | gn语法及在鸿蒙的使用
gn 存在的意义是为了生成 ninja,如果熟悉前端开发,二者关系很像 Sass和CSS的关系.
小帅聊鸿蒙
2025/03/26
2810
算法部署 | 万字长文带你从C++案例一步一步实操cmake(起飞系列)
你或许听过好几种Make工具,例如GNU Make ,QT的qmake ,微软的MS nmake,BSD Make(pmake),Makepp,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次Makefile,这将是一件让人抓狂的工作。
集智书童公众号
2021/07/30
1.6K0
Android JNI 开发
几乎稍有经验的Android开发,都会在工作中用到JNI的开发。即使工作中没有涉及到JNI的开发,在我们使用第三方的库时,也经常需要引入.so文件。
Oceanlong
2019/02/22
1.4K0
Android JNI 开发
Flutter鸿蒙终端一体化-混沌初开
flutter_flutter项目,这是我们整个工程的核心,但是很多人都倒在了第一步,其原因,就是——需要使用Dev分支!!! https://gitee.com/openharmony-sig/flutter_flutter/tree/dev/
用户1907613
2024/01/24
3.1K0
Flutter鸿蒙终端一体化-混沌初开
使用京东Taro开发鸿蒙PC(附鸿蒙版Taro环境搭建流程)
打开 DevEco,点击右上角的 Create Project,在 Application 处选择 Empty Ability,点击 Next,进入配置页面,根据需求调整内容,这里使用默认配置:
徐建国
2025/05/21
5330
使用京东Taro开发鸿蒙PC(附鸿蒙版Taro环境搭建流程)
推荐阅读
相关推荐
gtest单元测试框架介绍及简单使用
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • PawSQL优化算法剖析
    • 场景一:算术运算优化
    • 场景二:日期函数优化
    • 场景三:类型转换优化
    • 场景四:空值处理优化
    • 场景五:字符串操作优化
  • 算法的技术亮点
    • 1. 递归处理能力
    • 2. 运算符方向处理
    • 3. 比较运算符适配
    • 4. 上下文的自动化获取
    • 5. 特殊函数处理
  • 实际应用场景举例
  • 性能提升的量化分析
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档