使用 VerticaRoutableExecutor 类为可路由查询定义查询
使用 VerticaRoutableExecutor
类从单个节点直接访问表数据。 VerticaRoutableExecutor
仅在包含查询所需的所有数据的节点上直接查询 Vertica,从而避免产生与 Vertica 查询执行关联的分布式规划和执行成本。您可以使用 VerticaRoutableExecutor
联接表或使用 GROUP BY 子句,因为使用 VGet 无法执行这些操作。
使用 VerticaRoutableExecutor
类时,适用以下规则:
- 如果要联接表,您必须按联接谓词中引用的相同列集对要联接的所有表进行分段(使用哈希算法),除非要联接的表未分段。
- 联接 WHERE 子句中的多个条件必须使用 AND 联接在一起。在 WHERE 子句中使用 OR 会导致查询退化成多节点计划。如果数据存在于同一节点上,则可以在联接条件 outside 列上指定 OR、IN 列表或范围条件。
- 每个请求只能执行单个语句。不允许使用链接的 SQL 语句。
- 在由驱动程序生成的子查询中使用您的查询有助于确定该查询是否可以在单个节点上执行。因此,不能在语句的结尾包含分号,也不能包含使用双破折号的 SQL 注释 (
--
),因为这些会导致由驱动程序生成的查询失败。
可以通过对连接对象调用 createRoutableExecutor 方法来创建 VerticaRoutableExecutor。
createRoutableExecutor( schema‑name, table‑name )
例如:
VerticaRoutableConnection conn;
Map<String, Object> map = new HashMap<String, Object>();
map.put("customer_key", 1);
try {
conn = (VerticaRoutableConnection)
jdbcSettings.getConnection();
String table = "customers";
VerticaRoutableExecutor q = conn.createRoutableExecutor(null, table);
...
}...
如果 schema‑name 设置为空,则会使用搜索路径来查找表。
VerticaRoutableExecutor 方法
VerticaRoutableExecutor
包含以下方法:
-
[execute](#execute()
-
[关闭](#close())
有关此类的详细信息,请参阅 JDBC 文档。
执行
execute( query-string, { column, value | map } )
运行查询。
需要满足以下要求:
-
要执行的查询必须使用符合
VerticaRoutableExecutor
类规则的常规 SQL。例如,假如数据存在于单个节点上,则您可以添加限制和排序或使用聚合函数。 -
JDBC 客户端使用列/值或映射实参来确定应在哪个节点上执行查询。查询的内容必须使用您在列/值或映射实参中提供的相同值。
-
不能使用以下数据类型作为列值: * INTERVAL * TIMETZ * TIMESTAMPTZ
此外,如果表在具有以下数据类型的任何列上分段,则无法使用可路由查询 API 查询此表:
将查询发送到服务器之前,驱动程序不会验证查询的语法。如果表达式不正确,则查询会失败。
关闭
close()
通过释放由此 VerticaRoutableExecutor
使用的资源来关闭此 VerticaRoutableExecutor
。它不会关闭与 Vertica 的父 JDBC 连接。
getWarnings
getWarnings()
检索对此 VerticaRoutableExecutor
的调用所报告的第一个警告。其他警告均为链式,可使用 JDBC 方法 getNextWarning()
访问。
示例
以下示例显示如何使用 VerticaRoutableExecutor
执行同时使用 JOIN 子句和带有 GROUP BY 子句的聚合函数的查询。此示例还显示如何创建客户表和销售表,并对这些表进行分段,以便可以使用 VerticaRoutableExecutor
类联接这些表。此示例使用 VMart 架构中的 date_dimension
表来显示如何联接未分段的表上的数据。
-
创建
customers
表以存储客户详细信息,然后创建在表的customer_key
列上分段的投影:=> CREATE TABLE customers (customer_key INT, customer_name VARCHAR(128), customer_email VARCHAR(128)); => CREATE PROJECTION cust_proj_b0 AS SELECT * FROM customers SEGMENTED BY HASH (customer_key) ALL NODES; => CREATE PROJECTION cust_proj_b1 AS SELECT * FROM customers SEGMENTED BY HASH (customer_key) ALL NODES OFFSET 1; => CREATE PROJECTION cust_proj_b2 AS SELECT * FROM customers SEGMENTED BY HASH (customer_key) ALL NODES OFFSET 2; => SELECT start_refresh();
-
创建
sales
表,然后创建在其customer_key
列上分段的投影。由于customer
和sales
表按同一个键进行分段,因此您稍后可以使用VerticaRoutableExecutor
可路由查询查找来联接这两个表。=> CREATE TABLE sales (sale_key INT, customer_key INT, date_key INT, sales_amount FLOAT); => CREATE PROJECTION sales_proj_b0 AS SELECT * FROM sales SEGMENTED BY HASH (customer_key) ALL NODES; => CREATE PROJECTION sales_proj_b1 AS SELECT * FROM sales SEGMENTED BY HASH (customer_key) ALL NODES OFFSET 1; => CREATE PROJECTION sales_proj_b2 AS SELECT * FROM sales SEGMENTED BY HASH (customer_key) ALL NODES OFFSET 2; => SELECT start_refresh();
-
添加一些示例数据:
=> INSERT INTO customers VALUES (1, 'Fred', 'fred@example.com'); => INSERT INTO customers VALUES (2, 'Sue', 'Sue@example.com'); => INSERT INTO customers VALUES (3, 'Dave', 'Dave@example.com'); => INSERT INTO customers VALUES (4, 'Ann', 'Ann@example.com'); => INSERT INTO customers VALUES (5, 'Jamie', 'Jamie@example.com'); => COMMIT; => INSERT INTO sales VALUES(1, 1, 1, '100.00'); => INSERT INTO sales VALUES(2, 2, 2, '200.00'); => INSERT INTO sales VALUES(3, 3, 3, '300.00'); => INSERT INTO sales VALUES(4, 4, 4, '400.00'); => INSERT INTO sales VALUES(5, 5, 5, '400.00'); => INSERT INTO sales VALUES(6, 1, 15, '500.00'); => INSERT INTO sales VALUES(7, 1, 15, '400.00'); => INSERT INTO sales VALUES(8, 1, 35, '300.00'); => INSERT INTO sales VALUES(9, 1, 35, '200.00'); => COMMIT;
-
创建 VMart
date_dimension
表的未分段投影以在此示例中使用。调用元函数 START_REFRESH 来取消现有数据的分段:=> CREATE PROJECTION date_dim AS SELECT * FROM date_dimension UNSEGMENTED ALL NODES; => SELECT start_refresh();
现在,您可以使用 customer
、sales
和 date_dimension
数据创建如下可路由查询查找:使用联接和 group by 子句查询客户表并返回给定客户每天的总购买量:
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import com.vertica.jdbc.kv.*;
public class verticaKV_doc {
public static void main(String[] args) {
com.vertica.jdbc.DataSource jdbcSettings
= new com.vertica.jdbc.DataSource();
jdbcSettings.setDatabase("VMart");
jdbcSettings.setHost("vertica.example.com");
jdbcSettings.setUserID("dbadmin");
jdbcSettings.setPassword("password");
jdbcSettings.setEnableRoutableQueries(true);
jdbcSettings.setFailOnMultiNodePlans(true);
jdbcSettings.setPort((short) 5433);
VerticaRoutableConnection conn;
Map<String, Object> map = new HashMap<String, Object>();
map.put("customer_key", 1);
try {
conn = (VerticaRoutableConnection)
jdbcSettings.getConnection();
String table = "customers";
VerticaRoutableExecutor q = conn.createRoutableExecutor(null, table);
String query = "select d.date, SUM(s.sales_amount) as Total ";
query += " from customers as c";
query += " join sales as s ";
query += " on s.customer_key = c.customer_key ";
query += " join date_dimension as d ";
query += " on d.date_key = s.date_key ";
query += " where c.customer_key = " + map.get("customer_key");
query += " group by (d.date) order by Total DESC";
ResultSet rs = q.execute(query, map);
while(rs.next()) {
System.out.print("Date: " + rs.getString("date") + ": ");
System.out.println("Amount: " + rs.getString("Total"));
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
示例代码生成如下输出:
Date: 2012-01-15: Amount: 900.0
Date: 2012-02-04: Amount: 500.0
Date: 2012-01-01: Amount: 100.0
注意
您的输出可能会有所不同,因为 VMart 架构会在date_dimension
表中随机生成日期。