写点什么

如何使用参数化查询提高 Cypher 查询的性能

  • 2022 年 4 月 12 日
  • 本文字数:1935 字

    阅读完需:约 6 分钟

本文分享自华为云社区《使用参数化查询提高Cypher查询的性能:以华为云图引擎GES为例》,作者: 蜉蝣与海。


在 DBMS 中,参数化查询被视为一种有效预防 SQL 注入攻击的手段。华为云图引擎 GES 提供对 gremlin 和 cypher 查询语言的参数化查询支持,使用参数化查询不仅可以防止前端用户随意输入恶意指令影响语句执行,还可以有效利用查询编译缓存,提高查询性能。


参数化查询(Parameterized Query),Wiki 中的解释是:客户端在向数据服务端发送和请求查询语句时,在需要填入数值或者用户输入的字符串数据的地方,使用一个变量名来替代,并在请求体中解释每个变量名所指代的内容。在这种情况下,由于变量名指代的内容不会参与 SQL 语言的查询编译,即使用户输入数据中包含一些破坏性的指令,也不会被数据库运行。


举例说明,使用 Cypher-JDBC-Driver 访问华为云图引擎,可以进行对应的参数设置:

public static void main(String[] args) throws ClassNotFoundException {    Class.forName("com.huawei.ges.jdbc.Driver");    String url = "jdbc:ges:http://{{graph_ip}}:{{graph_port}}/ges/v1.0/{{project_id}}/graphs/{{graph_name}}/action?action_id=execute-cypher-query";    url = url.replace("{{graph_ip}}", ip).replace("{{graph_port}}",port + "").replace("{{project_id}}", projectId).replace("{{graph_name}}", graphName);    Properties prop = new Properties();    prop.setProperty("X-Auth-Token", token);    try(Connection conn = DriverManager.getConnection(url,prop)){        String query = "match (n:movie)  where n.genres=? return n.title";        try(PreparedStatement stmt = conn.prepareStatement(query)){            stmt.setString(1, "Comedy");            try(ResultSet rs = stmt.executeQuery()){                while(rs.next()) {                    System.out.println(rs.getString("n.title"));                }            }        }    } catch (SQLException e) {        // do something for e.    }}
复制代码

其中查询语句中的问号即是 JDBC 风格的参数化查询变量,后面代码中通过 setString 方法为其设置一个值“Comedy”。此外,图引擎也支持 restful api 风格的参数化查询,详见官网文档


同时,参数化查询可以使得不同的用户输入使用同一条参数化查询语句执行,可以高效利用数据库查询缓存,节省了查询编译时间,从而提升了查询性能。例如,下图是使用 Freebase 数据集构造的若干 2 跳 3 跳查询,在华为云图引擎 GES 中运行, 参数化查询前后 QPS 的变化。可以看到使用参数化查询,qps 获得了 2-8 倍的提升。



为什么参数化查询可以提高查询 qps?首先要简单介绍下数据服务在收到查询语句后都做了什么。在数据管理领域,数据服务接收到查询语句,往往会进行下列步骤: 词法 &语法解析,查询计划生成,查询计划执行,如图。



这里简单说一下查询计划生成。现在大多数查询计划的生成策略,要么是基于代价的查询计划生成,要么是基于规则的查询计划生成,或者二者组合使用。而不管是哪种查询计划生成,都是偏向计算密集型的任务,比较耗费服务器的计算资源,同一时间系统只能并行处理有限数目的查询计划生成任务。在计划生成器内部,大多数数据库都会内置查询缓存,即在一定的时间范围内,同一条查询语句输入计划器,计划器优先从查询缓存中检查有无可用计划,如果缓存中生成的计划时间太长或者无可用计划,才会真正执行计划生成的过程。


因此使用参数化查询时,由于使用不同参数的查询语句语句体相同,在查询编译阶段更容易被认为是同一条查询语句, 从而实现“多次查询,一次编译”的效果,也就提高了查询编译效率。


附录:

Freebase 数据集属性图格式规模:

查询语句:2hop_Q1: match (n1)-[r]->(m1)-->(p1) where id(n1)=$vertex return id(p1) limit 1002hop_Q2: match (n1)-[r]->(m1)-->(p1) where id(n1)=$vertex return p1.name limit 1002hop_Q3: match(n)-[r]->(m)-->(p) where id(n)=$vertex and m.games > 10 and p.name contains 'NBA' return p3hop_Q1: match (n1)-[r1]-(m1)-[r2]-(p1)--(p2) where id(n1)=$vertex and m1.game > 0 return id(p2) limit 1003hop_Q2: match (n1)-[r1]-(m1) match (m1)-[r2]-(p1) match (p1)--(p2) where id(n1)=$vertex and m1.games > 0 return id(p2)


相关参考:

[1]参数化查询_百度百科:https://baike.baidu.com/item/%E5%8F%82%E6%95%B0%E5%8C%96%E6%9F%A5%E8%AF%A2/4841802?fr=aladdin

[2]GES cypher API: https://support.huaweicloud.com/api-ges/ges_03_0212.html

[3]Github - opencypher:https://github.com/opencypher/openCypher


点击关注,第一时间了解华为云新鲜技术~​

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
如何使用参数化查询提高Cypher查询的性能_参数化_华为云开发者社区_InfoQ写作平台