McoDistributedSqlEngine
SmartESQL 分布式 SQL 引擎为 SmartEDB 集群安装提供了对数据库分片架构的有限支持。
有限支持
为何有限制?
大多数成熟的分布式数据库引擎(例如 Oracle 中的引擎)通常会基于查询树和数据分布统计信息或其他有关数据在分片之间分布的情况,以创建执行计划,其中包含“映射-归约”风格的操作。
SmartESQL 分布式引擎只是在每个节点上针对该节点的分片执行查询,并在可能的情况下合并从多个节点收到的结果集。有时合并无法实现,例如计算平均值。更多时候,引擎没有足够的信息来确保合并后的结果集是正确的。分布式 SQL 引擎采取了最乐观的方法,即假定应用程序在分片之间分布了数据,并创建了 SQL 查询以避免合并问题。
查询
分布式 SQL 引擎会将查询发送至网络中的一个节点,或者将查询广播至所有节点。通过查询前缀指定节点。为了控制数据的分布,应用程序必须要么在本地将数据加载到每个分片,要么在插入语句中指定节点 ID(编号)。例如:
10:insert into T values (…)
应用程序在选择特定节点上插入的记录时,可以在选择条件中明确使用当前节点 ID(%# 表示当前节点 ID,%@ 表示分片数)。例如:
insert into hist_cpvehicleid_jj
select * from foreign table (path='/home/usr/shea2.csv', skip=1)
as hist_cpvehicleid_jj
where mod(hashcode(fstr_vechileid), %#)=%@;
如果未使用上述任何一种方法,分布式 SQL 将在所有节点上广播插入操作。支持以下查询类型:
select * from T;
*:select * from T;
:与上述情况类似,在所有节点上运行该语句。N:select * from T;
:在节点 N(节点从 1 开始编号)上执行该语句。?:select * from T;
:在任何节点上执行该语句。目前,SQL 以循环方式选取节点,从而实现了一种简单的负载均衡方案。
一旦查询被执行且在每个节点上创建了结果集,分布式 SQL 引擎就会从所有节点收集结果数据集。如果查询包含聚合或排序子句,或者序列函数(对类型为序列的字段进行操作的统计函数;详情请参阅第 3 章“用于 SQL 的基于向量的统计函数”部分),则会合并结果集。分布式 SQL 引擎目前支持以下聚合:
- COUNT
- MIN
- MAX
- SUM (聚合操作数为一列)带或不带
group by
子句
CSV 导入
分布式 SQL 引擎支持在从 CSV 文件导入数据或通过应用程序代码导入数据时定义分片条件。通过以下 SQL 语句指定 CSV 导入数据的分片:
select from foreign table (path='csv-file', skip=n) as PatternTable
where distribution-condition
特殊伪参数
如上所述,分布式 SQL 引擎还支持特殊伪参数 %@ 和 %#。前者对应节点编号(从零开始);后者用于指定节点总数。例如:
echo "insert into table_name
select * from foreign table (path='table_name_file.csv', skip=1) as table_name
where mod(instrument_sid/$chunk_size,%#)=%@;"
> loadrisk.sql
./xsql.sh loadrisk.sql
xsql.sh
脚本按如下方式调用分布式 SQL 引擎:
xsql @node1 @node2 ... @nodeN $@
当应用程序从流(如下例中的套接字)或任何其他来源读取输入数据时,会通过类似于以下代码片段的代码将其插入数据库:
table_name tb;
socket_read(s, &tb);
engine.execute("insert into table_name(starttime, endtime, book1, book2, instrument_sid)
values (%l,%l,%s,%s,%l)", tb.starttime, tb.endtime, tb.book1, tb.book2,
tb.instrument_sid);
以下代码片段会在应用程序的代码中添加一个分片条件:
char sql[MAX_SQL_STMT_LEN];
table_name tb;
socket_read(s, &tb);
sprintf(sql, "%d:insert into table_name (starttime,endtime,book1,book2,instrument_sid)
values (%%l,%%l,%%s,%%s,%%l)", tb.instrument_sid%n_nodes);
engine.execute(sql, tb.starttime, tb.endtime, tb.book1, tb.book2, tb.instrument_sid);
引擎当前不支持
- 使用 DISTINCT 限定符合并聚合;
- 对复杂表达式(如 X+Y)进行聚合,除非排序列或分组列包含在结果集中或选择语句中;
例如(以 Metatable 为例):
select Metatable.*,FieldNo+FieldSize as ns from Metatable order by ns;
或
select T.*,x+y as xy from T order by xy;
- 除了两种情况外,基于哈希的聚合(
seq_hash_aggregate_*
):
- 当哈希表所基于的数据属于单个分片(如下例中的交换)时:
select seq_hash_agg_sum(price,exchange) from Quote;
- 如果将序列转换为水平表示形式,那么查询就可以在任何数据分布的情况下运行:
select flattened seq_hash_agg_sum(price,exchange) from Quote;
- 平均数(avg)聚合。除非来自不同节点的组不重叠。例如,以下布局是受支持的:
Node1:
Symbol Price
AAA 10.0
AAA 12.0
AAA 9.0
BBB 11.0
BBB 10.0
BBB 10.0
Node2:
Symbol Price
CCC 8.0
CCC 7.0
CCC 10.0
DDD 15.0
DDD 14.0
DDD 13.0
select avg(Price) from Quote group by Symbol;
示例
其他有效和无效陈述的示例有:
select * from T; // 支持;结果合并
select * from T order by y; // 支持;从所有节点对结果进行排序
select * from T order by x+y; // 不支持复杂表达式
select sum(x) from T; // 支持;结果合并
select avg(x) from T; // 平均数合并目前不受支持
select y,sum(x) from T group by y; // 支持;组和聚合被合并
select sum(x) from T group by y; // 支持;“分组依据”列必须包含在“from”列表中
select sum(x*2) from T; // 不支持复杂表达式
select ifnull(sum(x), 0) from T; // 支持;结果合并
select seq_sum(x) from T; // 支持;结果合并
select seq_hash_agg_sum(x,y) from T; //不支持哈希聚合的合并
select flattened seq_hash_agg_sum(x,y) from T; // 支持;排序、分组并汇总