业务背景
在实际业务中,用户会基于不同的产品分别构建实时数仓和离线数仓。其中,实时数仓强调数据能够快速入库,且在入库的第一时间就可以进行分析,低时延的返回分析结果。而离线数仓强调复杂任务能够稳定的执行完,需要更好的内存管理。
ByConity 是一款开源云原生数据仓库,可以满足用户的多种数据分析场景。ByConity 增加了 bsp 模式:可以进行 task 级别的容错;更细粒度的调度;基于资源感知的调度。希望通过 bsp 能力,把数据加工(T)的过程转移到ByConity 内部,能够一站式完成数据接入、加工和分析。
测试环境
这里准备了1t的数据测试内容,并已经建立好了测试数据。
这里要把22改成23 。
上手测试
先登录进数据库,并设置语言‘ANSI’
先从sql21 开始这个比较简单。
select *
from(select w_warehouse_name
,i_item_id
,sum(case when (cast(d_date as date) < cast ('2000-03-11' as date))
then inv_quantity_on_hand
else 0 end) as inv_before
,sum(case when (cast(d_date as date) >= cast ('2000-03-11' as date))
then inv_quantity_on_hand
else 0 end) as inv_after
from inventory
,warehouse
,item
,date_dim
where i_current_price between 0.99 and 1.49
and i_item_sk = inv_item_sk
and inv_warehouse_sk = w_warehouse_sk
and inv_date_sk = d_date_sk
and d_date between (cast ('2000-03-11' as date) - INTERVAL '30' DAY)
and (cast ('2000-03-11' as date) + INTERVAL '30' DAY)
group by w_warehouse_name, i_item_id) x
where (case when inv_before > 0
then inv_after / inv_before
else null
end) between 2.0/3.0 and 3.0/2.0
order by w_warehouse_name
,i_item_id
limit 100;
经测试,0.2秒返回数据370000行。
100 rows in set. Elapsed: 0.237 sec. Processed 373.07 thousand rows, 10.54 MB (1.58 million rows/s., 44.55 MB/s.)
测试下复杂的sql语句,如sql 78
with ws as
(select d_year AS ws_sold_year, ws_item_sk,
ws_bill_customer_sk ws_customer_sk,
sum(ws_quantity) ws_qty,
sum(ws_wholesale_cost) ws_wc,
sum(ws_sales_price) ws_sp
from web_sales
left join web_returns on wr_order_number=ws_order_number and ws_item_sk=wr_item_sk
join date_dim on ws_sold_date_sk = d_date_sk
where wr_order_number is null
group by d_year, ws_item_sk, ws_bill_customer_sk
),
cs as
(select d_year AS cs_sold_year, cs_item_sk,
cs_bill_customer_sk cs_customer_sk,
sum(cs_quantity) cs_qty,
sum(cs_wholesale_cost) cs_wc,
sum(cs_sales_price) cs_sp
from catalog_sales
left join catalog_returns on cr_order_number=cs_order_number and cs_item_sk=cr_item_sk
join date_dim on cs_sold_date_sk = d_date_sk
where cr_order_number is null
group by d_year, cs_item_sk, cs_bill_customer_sk
),
ss as
(select d_year AS ss_sold_year, ss_item_sk,
ss_customer_sk,
sum(ss_quantity) ss_qty,
sum(ss_wholesale_cost) ss_wc,
sum(ss_sales_price) ss_sp
from store_sales
left join store_returns on sr_ticket_number=ss_ticket_number and ss_item_sk=sr_item_sk
join date_dim on ss_sold_date_sk = d_date_sk
where sr_ticket_number is null
group by d_year, ss_item_sk, ss_customer_sk
)
select
ss_sold_year, ss_item_sk, ss_customer_sk,
round(ss_qty/(coalesce(ws_qty,0)+coalesce(cs_qty,0)),2) ratio,
ss_qty store_qty, ss_wc store_wholesale_cost, ss_sp store_sales_price,
coalesce(ws_qty,0)+coalesce(cs_qty,0) other_chan_qty,
coalesce(ws_wc,0)+coalesce(cs_wc,0) other_chan_wholesale_cost,
coalesce(ws_sp,0)+coalesce(cs_sp,0) other_chan_sales_price
from ss
left join ws on (ws_sold_year=ss_sold_year and ws_item_sk=ss_item_sk and ws_customer_sk=ss_customer_sk)
left join cs on (cs_sold_year=ss_sold_year and cs_item_sk=ss_item_sk and cs_customer_sk=ss_customer_sk)
where (coalesce(ws_qty,0)>0 or coalesce(cs_qty, 0)>0) and ss_sold_year=2000
order by
ss_sold_year, ss_item_sk, ss_customer_sk,
ss_qty desc, ss_wc desc, ss_sp desc,
other_chan_qty,
other_chan_wholesale_cost,
other_chan_sales_price,
ratio
LIMIT 100 ;
设置SETTINGS
bsp_mode = 1,
distributed_max_parallel_size = 4; 这里提示内存不足。
改成24之后,
可以成功获取数据。
测试下sql 79 通过限制内容大小实现内存溢出。
select
c_last_name,
c_first_name,
substr(s_city,1,30),
ss_ticket_number,amt,profit
from
(
select
ss_ticket_number,
ss_customer_sk,
store.s_city,
sum(ss_coupon_amt) amt,
sum(ss_net_profit) profit
from store_sales,date_dim,store,household_demographics
where
store_sales.ss_sold_date_sk = date_dim.d_date_sk
and store_sales.ss_store_sk = store.s_store_sk
and store_sales.ss_hdemo_sk = household_demographics.hd_demo_sk
and (household_demographics.hd_dep_count = 6 or household_demographics.hd_vehicle_count > 2)
and date_dim.d_dow = 1
and date_dim.d_year in (1999,1999+1,1999+2)
and store.s_number_employees between 200 and 295
group by ss_ticket_number,ss_customer_sk,ss_addr_sk,store.s_city) ms,customer
where ss_customer_sk = c_customer_sk
order by c_last_name,c_first_name,substr(s_city,1,30), profit
LIMIT 100
SETTINGS
max_memory_usage=40000000000;
这里先设置40000000000; 能正常获取数据。
改小点35000000000;依然能获取数据。
在改小点,2000000000;成功触发oom,内存溢出。
此时增加bsp_mode = 1,
distributed_max_parallel_size = 12; 成功获取数据,解决oom问题。
通过大模型解析sql
这里使用kimi 询问sql 79 是什么意思。
这段SQL代码是一个查询语句,用于从数据库中检索特定信息,并对其进行排序和限制结果数量。下面是对这个SQL语句的逐步解释:
- 查询字段:
c_last_name和c_first_name:客户姓氏和名字。substr(s_city,1,30):店铺所在城市名称的前30个字符。ss_ticket_number:销售票据编号。amt:优惠券金额总和。profit:净利润总和。- 子查询:
- 子查询从
store_sales、date_dim、store和household_demographics四个表中查询数据。 - 连接条件包括销售日期、店铺编号、家庭统计编号等。
- 过滤条件包括:
hd_dep_count(家庭统计中的依赖人数)等于6或hd_vehicle_count(车辆数)大于2。d_dow(星期几)为1(通常是星期一)。d_year在1999年、2000年、2001年之间。s_number_employees(店铺员工数)在200到295之间。- 对结果进行分组,按
ss_ticket_number、ss_customer_sk、ss_addr_sk和store.s_city。 - 主查询:
- 将子查询的结果(别名为
ms)与customer表连接,通过ss_customer_sk和c_customer_sk匹配。 - 过滤后的结果按客户姓氏、名字、城市和利润排序。
- 结果限制:
- 使用
LIMIT 100限制查询结果为前100条。 - 设置:
max_memory_usage=40000000000:设置查询过程中可以使用的最大内存量。bsp_mode = 1:启用批量同步处理模式,这是一种数据处理模式,可以提高大规模数据处理的效率。distributed_max_parallel_size = 12:设置分布式查询中的最大并行度为12,意味着查询可以同时在最多12个并行任务中执行。
总的来说,这个SQL查询是为了找出符合特定条件的客户,他们在特定日期的购买行为(使用优惠券和产生的利润),并且这些客户的家庭统计信息符合特定的条件。查询结果按照客户的姓名和城市进行排序,并限制输出结果的数量。同时,通过特定的设置来优化查询性能和资源使用。
可以看出 大模型可以基本上判断出sql 的大致意义。
使用总结
传统架构中,之所以要分别建设离线数仓和实时数仓,是因为常见的 OLAP 产品不擅长处理大量的复杂查询,很容易把内容打满任务中断,甚至造成宕机。
ByteHouse 具备 BSP 模式,支持将查询切分为不同的 stage,每个 stage 独立运行。在此基础上,stage 内的数据也可以进行切分,并行化不再受节点数量限制,理论上可以无限扩展,从而大幅度降低峰值内存。是一个使用非常良好的数据仓库,无论是上手难度还是查询速度。
文章参考: