SQL 提速:有关联维表的高并发查询

问题描述

SQL 提速:高并发帐户查询(下面简称前文)中讨论过单表高并发查询方案。有时情况复杂,查询还会涉及关联运算。比如:帐户查询时,明细数据还要与网点表等维表做关联计算,最终结果中要包含维表的字段,例如网点名称、地址、电话等。数据结构如下图:

..

SQL 语句写出来大概是这个样子:

select d.id,d.amt,d.detail_date,s.name,s.phone_number,s.address,… from detail d

       left join store s on d.store_id=s.id

where d.id='1010087'

and d.detail_date>= to_date('2021-01-10', 'yyyy-MM-dd')

and d.detail_date<to_date('2021-01-25', 'yyyy-MM-dd')

and …

为了提高查询响应速度,一般都会对 detail 表的帐号 id 字段建索引如下:

create index index_detail_1 on detail(id)

 

提速方案

一、快速查找,内存关联

通常,这些用作代码的维表都很小,可以全部预读入到内存中并建立好索引。然后使用前文所述的方案,快速查找满足条件的明细数据后,再与这些内存维表做关联运算。因为维表已经建好索引,而且读出来的明细数据量也很小,关联的性能损失基本可以忽略不计,即使有多个关联维表也仍然会非常快,可以满足秒级响应要求。

 

二、新增数据

按前文的方案即可。

代码示例

一、数据预处理,有序行存、建立索引

参见前文。

 

二、索引预加载、维表预加载

在系统初始化或者索引、维表发生变动时,要加载到内存中,每次查询计算的时候可以节省加载时间。


A

B

1

if !ifv(detail)

=file("detail.ctx").open().index@3(index_id)

2


=env(detail,B1)

3

if !ifv(store)

=file("store.btx").import@b(id,name,...).keys(id)

4


=env(store,B3)

A1:判断全局变量 detail 是否存在,如果存在,表示已经加载了索引。

B1:如果全局变量 detail 不存在,那么打开组表加载三级索引。@2 或者 @3 表示加载 2 或者 3 级索引。3 级索引性能更好,但需要更大的内存。具体加载 2 级还是 3 级,需要根据索引的大小和内存的容量确定。

B2:全局变量 detail 赋值为 B1。

A3-B4:预加载网点维表,带索引的主键是网点编号 id。

 

三、帐户查询、关联计算

因为预先加载了带索引的明细表和维表,所以查询代码非常简单:


A

1

=detail.icursor(;id==1010087   &&  detail_date>=date("2021-01-10")   && detail_date<date("2021-01-25") && …,index_id).fetch()

2

=A1.switch(store_id,store)

3

return A3.new(id,store_id.store_id:store_id,store_id.store_name:store_name,…,amt,detail_date,…)

A1:icursor 是带索引的游标。实际应用中,帐户 id、时间段等条件,要通过参数传入。

A2:读入内存中的明细数据,和网点维表做关联计算。

A3:引用关联字段,返回查询结果。

 

四、新增数据

代码参见前文。