高大上技术之sql解析
Question: 为何sql解析和高大上有关系?
Answer:因为数据库永远都是系统的核心,CRUD如此深入码农的内心。。。如果能把CRUD改造成高大上技术,如此不是造福嘛。。。
CRUD就是Create, Read, Update, Delete,转换成sql语句就是insert, select, update, delete
普通场景下,insert也就是一个insert了,没什么高深。。。
高并发场景下,insert就不是一个insert了,而是千千万万个insert。。。可以用到的技术有排队、分表、分区、分仓、缓存同步
普通场景下,select也就是一个select了,没什么高深。。。
高并发场景下,select就不是一个select了,而是千千万万,再千千万万个select。。。可以用到的技术有缓存、普通读写分离、深入读写分离、不锁、past锁、还有分表、分区、分仓。。。
你说这么多东西,是全部在一个sql中全部自动化掉好呢,还是让我们码农一个一个考虑,再一个一个写成代码逻辑的好?
肯定两种声音都有,还肯定有第三种声音。。。所以我还是照着我自己的思路来说吧,你们随便发挥想象。。。
我要让一个sql全部解决上面的效果,或者接近上面的效果
如何解决,那就是,以SELECT语句为例
- 解析SELECT语句
- 解析牵涉到的表、字段、主键
- 解析是否用到了自己扩展的dsl函数
- 找到相应表的分区函数
- 找到相应表的缓存配置
- 找到dsl函数对应的真实函数
- 其他
比如有2个SELECT语句:
- SELECT UserID, UserName, Age FROM Users WHERE UserID='某个guid'
- SELECT COUNT(1) FROM Users
很简单的两句sql,可是Users是个虚拟表,真实表有16个表:Users.[A-F], Users.[0-9],分表策略为根据主键ID的第一个字母来分表, 因此:
- 第一句sql需要先解析where条件中UserID='guid'这个UserID是否为pkid,以及这个'guid'的值,然后根据guid的值调用分表策略函数得到相应的分表后缀,然后用类似下面这个sql来真实查询:SELECT UserID, UserName, Age FROM [Users.A] WHERE UserID='axxxxx-xxxxx-xxxx-xx'
- 第二句sql其实是最终变成了16条sql来得到各个分表的count值,然后在程序中累加这些分表的count值
其他:
- 其他类似缓存、队列、自定义的扩展函数,都类似于上可以得到解决。
由于只是个demo,所以没有实现上述全部功能,我们只说下关键原理、和代码。。。
我们用antlr来做词法解析、语法解析,然后再用tree walker把antlr解析出来的东西转换为我们要的数据结构,比如:SelectTerms, TableName, WhereClause, OrderByClause等
奥,我们还得写一个规则文件让Antlr吃进去,然后antlr就能调用tree walker生成我们要的数据结构了
(大家赶紧补下编译原理之类的基础知识以及ANTLR知识)
grammar SelectSQL; /*
* Parser Rules
*/ compileUnit
: start
; /*
* Lexer Rules
*/ WS
: [ \t\n\r]+ -> skip
; COMMA:',';
SELECT: 'SELECT';
STAR:'*';
FROM:'FROM';
WHERE:'WHERE';
ORDERBY:'ORDER BY';
DIRECTION:'ASC'|'DESC';
CHAR: 'a'..'z'|'A'..'Z';
NUM: ''..'';
STRING:'\'' .*? '\'';
LB:'(';
RB:')';
LBRACE:'[';
RBRACE:']';
CONDITIONS_OPERATOR
:'AND'
|'OR'
;
CONDITION_OPERATOR
:'='
|'>'
|'<'
|'<>'
|'!='
|'>='
|'<='
;
FCOUNT:'COUNT'; start
:statement_list
; statement_list
:statement statement*
; statement
:selectStatement
; selectStatement
:selectStmt fromStmt whereStmt? orderbyStmt?
; selectStmt
:SELECT columns
; columns
:column (COMMA column)*
; column
: identifier
| LBRACE identifier RBRACE
| functionStmt
| STAR
; functionStmt
:function LB (parameters) RB
; function
:FCOUNT
; parameters
: parameter (COMMA parameter)*
; parameter
: identifier
| integer
| string
| STAR
; fromStmt
:FROM table
; table
: identifier
| LBRACE identifier RBRACE
; whereStmt
: WHERE conditions
; conditions
: condition (CONDITIONS_OPERATOR condition)*
; condition
:left CONDITION_OPERATOR right
; left
: parameter
; right
: parameter
; orderbyStmt
:ORDERBY sortStmt
; sortStmt
: sortCondition (COMMA sortCondition)*
; sortCondition
:sortColumn DIRECTION
; sortColumn
: identifier
| LBRACE identifier RBRACE
; identifier
:CHAR (CHAR|NUM)*
;
integer
:NUM+
;
string
: STRING
;
真心呼唤广大开发人员深入编译原理之类的基础技术!
在eclipse中输入解析sql文本后,会被解析成tree

开源世界真强大啊,有yacc, flex, bison, antlr这些现成的解析工具。
我们先在eclipse中把规则测试通过后,再把这个.g4规则文件拷贝到我们的visual studio中,如下:

然后只要这个g4文件一保存,antlr的vs插件就会自动根据规则文件生成相关名称的词法解析类、文法解析类、以及我们即将要改写的TreeListener

SelectSQLBaseListener:就是antlr插件自动生成的抽象类,我们的改动都是基于这个类,来做override改写(针对规则的enter/exit)
EnterXXXXX/ExitXXXX: 对应规则文件中的规则名称,Enter/Exit代表进入规则以及离开规则之前的行为动作
demo控制台程序运行输出效果:
输入SQL:
SELECT * FROM users
SELECT userId, userName FROM users
SELECT COUNT(1) FROM users
SELECT COUNT(*) FROM users
SELECT userId, userName FROM users ORDER BY userName DESC
SELECT userId, userName FROM users WHERE userId='' ORDER BY userName DESC
输出SQL:
select * from [users.0]
select * from [users.1]
select * from [users.2]
select * from [users.3]
select * from [users.4]
select * from [users.5]
select * from [users.6]
select * from [users.7]
select * from [users.8]
select * from [users.9]
select * from [users.a]
select * from [users.b]
select * from [users.c]
select * from [users.d]
select * from [users.e]
select * from [users.f]
select userId, userName from [users.0]
select userId, userName from [users.1]
select userId, userName from [users.2]
select userId, userName from [users.3]
select userId, userName from [users.4]
select userId, userName from [users.5]
select userId, userName from [users.6]
select userId, userName from [users.7]
select userId, userName from [users.8]
select userId, userName from [users.9]
select userId, userName from [users.a]
select userId, userName from [users.b]
select userId, userName from [users.c]
select userId, userName from [users.d]
select userId, userName from [users.e]
select userId, userName from [users.f]
select COUNT(1) from [users.0]
select COUNT(1) from [users.1]
select COUNT(1) from [users.2]
select COUNT(1) from [users.3]
select COUNT(1) from [users.4]
select COUNT(1) from [users.5]
select COUNT(1) from [users.6]
select COUNT(1) from [users.7]
select COUNT(1) from [users.8]
select COUNT(1) from [users.9]
select COUNT(1) from [users.a]
select COUNT(1) from [users.b]
select COUNT(1) from [users.c]
select COUNT(1) from [users.d]
select COUNT(1) from [users.e]
select COUNT(1) from [users.f]
select COUNT(*) from [users.0]
select COUNT(*) from [users.1]
select COUNT(*) from [users.2]
select COUNT(*) from [users.3]
select COUNT(*) from [users.4]
select COUNT(*) from [users.5]
select COUNT(*) from [users.6]
select COUNT(*) from [users.7]
select COUNT(*) from [users.8]
select COUNT(*) from [users.9]
select COUNT(*) from [users.a]
select COUNT(*) from [users.b]
select COUNT(*) from [users.c]
select COUNT(*) from [users.d]
select COUNT(*) from [users.e]
select COUNT(*) from [users.f]
select userId, userName from [users.0] order by userName DESC
select userId, userName from [users.1] order by userName DESC
select userId, userName from [users.2] order by userName DESC
select userId, userName from [users.3] order by userName DESC
select userId, userName from [users.4] order by userName DESC
select userId, userName from [users.5] order by userName DESC
select userId, userName from [users.6] order by userName DESC
select userId, userName from [users.7] order by userName DESC
select userId, userName from [users.8] order by userName DESC
select userId, userName from [users.9] order by userName DESC
select userId, userName from [users.a] order by userName DESC
select userId, userName from [users.b] order by userName DESC
select userId, userName from [users.c] order by userName DESC
select userId, userName from [users.d] order by userName DESC
select userId, userName from [users.e] order by userName DESC
select userId, userName from [users.f] order by userName DESC
select userId, userName from [users.0] WHERE userId='' order by userName DESC
select userId, userName from [users.1] WHERE userId='' order by userName DESC
select userId, userName from [users.2] WHERE userId='' order by userName DESC
select userId, userName from [users.3] WHERE userId='' order by userName DESC
select userId, userName from [users.4] WHERE userId='' order by userName DESC
select userId, userName from [users.5] WHERE userId='' order by userName DESC
select userId, userName from [users.6] WHERE userId='' order by userName DESC
select userId, userName from [users.7] WHERE userId='' order by userName DESC
select userId, userName from [users.8] WHERE userId='' order by userName DESC
select userId, userName from [users.9] WHERE userId='' order by userName DESC
select userId, userName from [users.a] WHERE userId='' order by userName DESC
select userId, userName from [users.b] WHERE userId='' order by userName DESC
select userId, userName from [users.c] WHERE userId='' order by userName DESC
select userId, userName from [users.d] WHERE userId='' order by userName DESC
select userId, userName from [users.e] WHERE userId='' order by userName DESC
select userId, userName from [users.f] WHERE userId='' order by userName DESC
希望大家能对基础技术真正感兴趣,赶紧学习编译原理、antlr吧。
很抱歉没能提供详细原理说明,大家baidubaidu就都有了。
代码下载 http://files.cnblogs.com/files/aarond/SQLParser_Select.rar
高大上技术之sql解析的更多相关文章
- 步步深入:MySQL架构总览->查询执行流程->SQL解析顺序
前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面这一篇博文了. 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来 ...
- SQL解析在美团的应用
https://tech.meituan.com/SQL_parser_used_in_mtdp.html 数据库作为核心的基础组件,是需要重点保护的对象.任何一个线上的不慎操作,都有可能给数据库带来 ...
- MySQL架构总览->查询执行流程->SQL解析顺序
Reference: https://www.cnblogs.com/annsshadow/p/5037667.html 前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后 ...
- 转载:一文详解SQL解析与应用
转载地址:http://www.elecfans.com/emb/20180618696111.html 数据库作为核心的基础组件,是需要重点保护的对象.任何一个线上的不慎操作,都有可能给数据库带来严 ...
- Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述
Spark SQL模块,主要就是处理跟SQL解析相关的一些内容,说得更通俗点就是怎么把一个SQL语句解析成Dataframe或者说RDD的任务.以Spark 2.4.3为例,Spark SQL这个大模 ...
- Oracle体系结构概述与SQL解析剖析
Oracle服务器 是一个数据库管理系统,它提供了一种全面.开放.集成的方法来管理信息. Oracle服务器由Oracle数据库和Oracle实例组成. oracle数据库软件和Oracle数据库软件 ...
- Pisa-Proxy 之 SQL 解析实践
SQL 语句解析是一个重要且复杂的技术,数据库流量相关的 SQL 审计.读写分离.分片等功能都依赖于 SQL 解析,而 Pisa-Proxy 作为 Database Mesh 理念的一个实践,对数据库 ...
- openGauss内核:SQL解析过程分析
摘要:在传统数据库中SQL引擎一般指对用户输入的SQL语句进行解析.优化的软件模块.SQL的解析过程主要分为:词法.语法和语义分析. 本文分享自华为云社区< openGauss内核分析(三):S ...
- 如何实现一个SQL解析器
作者:vivo 互联网搜索团队- Deng Jie 一.背景 随着技术的不断的发展,在大数据领域出现了越来越多的技术框架.而为了降低大数据的学习成本和难度,越来越多的大数据技术和应用开始支持SQL进 ...
随机推荐
- xcode添加音效
xcode添加背景音乐/音效 背景音乐:http://www.cnblogs.com/jiayongqiang/p/5476069.html 音效: 一.介绍: 又称“短音频”,通常在程序中的播放时长 ...
- 用C语言写的双色球
#include<stdio.h> #include<stdlib.h> #include<time.h> double jieguo(); void main() ...
- hdu 4268 Alice and Bob
Alice and Bob Time Limit : 10000/5000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Tota ...
- Java垃圾回收小结
一.如何确定某个对象是“垃圾”? 首先要搞清一个最基本的问题:如果确定某个对象是“垃圾”?既然垃圾收集器的任务是回收垃圾对象所占的空间供新的对象使用,那么垃圾收集器如何确定某个对象是“垃圾”?—即通过 ...
- Git 常用几个操作
获取 git clone git@github.com:XXX/learning.git 更新 git pull 添加 git add XXX 上传本地 git commit -m "ap ...
- Linux内核--网络栈实现分析(一)--网络栈初始化
本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏, ...
- redis和ssdb读取性能对比
最近关注了一下ssdb,它的特点是基于文件存储系统所以它支撑量大的数据而不因为内存的限制受取约束.从官网的测试报告来看其性能也非常出色和redis相当,因此可以使用它来代替redis来进行k-v数据业 ...
- Dynamic CRM 2013学习笔记(十七)JS读写各种类型字段方法及技巧
我们经常要对表单里各种类型的字段进行读取或赋值,下面列出各种类型的读写方法及注意事项: 1. lookup 类型 清空值 var state = Xrm.Page.getAttribute(" ...
- [stm32] 利用uC-BmpCvt软件生成uc-gui可调用的bmp图片
>_<:学习贴图[bmp图]:首先找一张bmp格式的图片,然后下载uC-BmpCvt软件,打开改图片 >_<:然后点击Image-Conver-Into-Best Palatt ...
- JsRender for index 循环索引使用说明
循环是模版引擎必不可少的一部分,而说起循环,会引出一个至关重要的因素:索引. 所谓索引,即循环次数,通过索引,可以获取当前循环是第几次. 如果读者阅读过官方文档,会见到如下获取索引的方式: data: ...