1、问题
SQL特征搜索是数据库产品中使用比较频繁的一个技术,在某些产品中的调用频率非常高,参考数据是一个普通SQL可能存在20个以上的关键字,而数据库流量可能达到每秒50万个请求以上。因此提升SQL特征搜索的效率是提升数据库产品质量中非常重要的一项工作,它可以直接降低性能损耗、减少内存占用、减少请求处理时间,提升产品的整体性能。
最简单直接的方案是通过字符串匹配匹配,以特征库作为匹配模版,对SQL的内容进行匹配。可以很直观的看出,这种方法的时间复杂度太高,难以支撑较高的性能需求
基于正则表达式匹配的SQL特征搜索看起来时间复杂度减少了一个指数级别,但是正则表达式的性能问题是众所周知的。
这个方案在其它厂商的数据库审计产品中使用了,不过需求上有所不同,在数据库审计不仅要求特征匹配,而且要求结构匹配。但是即使是这样,该方案仍然不能准确匹配到特征语法,例如其中的注释和字符串等内容,就很难通过正则表达式表示出来。
使用开源工具Druid对SQL进行分词处理,将所得的关键字或者标识符拿到特征库中进行hash对比。可以看到基本上对SQL扫描一遍就可以得到最终的结果,但是过程中产生了数个字符串对象(select、c_first…),当然也会进行相同多次的堆内存分配。
2、解决方案
本方案依据Postgresql语法手工对SQL进行分词处理,然后依据分词的偏移量直接计算对应关键字或者标识符的hash值,然后拿到特征库中进行搜索对比。可以看到同样是对SQL扫描一遍就可以得到最终的结果,但是过程中避免了多次的堆内存分配。
3、优点
经过相同环境下的测试对比,可知本方案在提高SQL特征搜索效率方面产生了较大的提升。而且由于词法分析的环节,准确率显然比正则表达式方式更高(可以处理注释)。下述表格中记录了相同测试条件下各个方案性能的对比:使用样例SQL进行单线程的性能测试。
SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, /* FOR UPDATE */ c_state, c_zip, c_phone, c_since, c_credit, c_credit_lim, c_discount, c_balance FROM bmsql_customer WHERE c_w_id = ? AND c_d_id = ? AND c_id = ? AND c_middle='FOR UPDATE' FOR UPDATE