业务场景的问题,我们有一个刷CUBE的SQL,是Oracle环境,平时跑70多分钟,

但是最近突然不动了,这个SQL需要算累计值,比如年累计客户数量。

累计值是什么意思呢?我们使用下面的数据来说明问题。

select '201901' as c_month, 100 as c_customers from dual union all
select '201902' as c_month, 102 as c_customers from dual union all
select '201903' as c_month, 120 as c_customers from dual union all
select '201904' as c_month, 111 as c_customers from dual union all
select '201905' as c_month, 155 as c_customers from dual union all
select '201906' as c_month, 199 as c_customers from dual; C_MONT C_CUSTOMERS
------ -----------
201901 100
201902 102
201903 120
201904 111
201905 155
201906 199

  

2019年1月,客户数量是100, 2019年2月,客户数量是102 ,

那么2019年1月的客户累计值是100,

2019年2月的客户年累计值是202(2019年1月的客户数量 + 2019年2月的客户数量),

2019年3月的客户年累计值是322(2019年1月的客户数量 + 2019年2月的客户数量+ 2019年3月的客户数量),

...

我使用如下的测试SQL来说明这个场景

create or replace view tab_test1 as
select '201901' as c_month, 100 as c_customers from dual union all
select '201902' as c_month, 102 as c_customers from dual union all
select '201903' as c_month, 120 as c_customers from dual union all
select '201904' as c_month, 111 as c_customers from dual union all
select '201905' as c_month, 155 as c_customers from dual union all
select '201906' as c_month, 199 as c_customers from dual union all
select '201907' as c_month, 108 as c_customers from dual; create view tab_test2 as
select '20190131' as monthlastday from dual union all
select '20190228' as monthlastday from dual union all
select '20190331' as monthlastday from dual union all
select '20190430' as monthlastday from dual union all
select '20190531' as monthlastday from dual union all
select '20190630' as monthlastday from dual union all
select '20190731' as monthlastday from dual; select *
from tab_test1 a
join tab_test2 b
on to_date(c_month,'yyyymm') <= to_date(b.monthlastday,'yyyymmdd')
and to_date(c_month,'yyyymm') >= trunc(to_date(b.monthlastday,'yyyymmdd'),'yyyy')
order by b.monthlastday , a.c_month; C_MONT C_CUSTOMERS MONTHLAS
------ ----------- --------
201901 100 20190131
201901 100 20190228
201902 102 20190228
201901 100 20190331
201902 102 20190331
201903 120 20190331
201901 100 20190430
201902 102 20190430
201903 120 20190430
201904 111 20190430
201901 100 20190531 C_MONT C_CUSTOMERS MONTHLAS
------ ----------- --------
201902 102 20190531
201903 120 20190531
201904 111 20190531
201905 155 20190531
201901 100 20190630
201902 102 20190630
201903 120 20190630
201904 111 20190630
201905 155 20190630
201906 199 20190630
201901 100 20190731 C_MONT C_CUSTOMERS MONTHLAS
------ ----------- --------
201902 102 20190731
201903 120 20190731
201904 111 20190731
201905 155 20190731
201906 199 20190731
201907 108 20190731 已选择 28 行。

  

从上面SQL返回的数据能看出来,monthlastday 字段分组,汇总c_customers,就能很轻松算出年累计值。但是如果a表数据太大,无法走hash 关联。

所以需要通过某种方法改成等值关联。

1. 先创建一个时间维表,可以通过树形查询生成一个时间维度表,由于我的测试数据自小粒度是到月的,所以我的日期维度表也是到月的。

create or replace view tab_test3 as
select extract(year from c_date) as c_year,
extract(month from c_date) as c_month,
to_char(c_date,'yyyymm') as c_month2
from (select add_months(date'2019-01-01',level -1 ) as c_date
from dual
connect by level <= 8);

  

2. 通过时间维度表自关联出累计月份对应的日期。

下面SQL,同构过滤t1 表的c_month2 字段,就可以拿到任意月份的累计月份了。比如2019-07月的累计月份是2019年 1-7月份

select t1.c_month2 as groupcolumn,t2.c_month2 joincolumn
from tab_test3 t1
join tab_test3 t2
on t1.c_year = t2.c_year
and t1.c_month2 >= t2.c_month2
order by 1,2 GROUPC JOINCO
------ ------
201901 201901
201902 201901
201902 201902
201903 201901
201903 201902
201903 201903
201904 201901
201904 201902
201904 201903
201904 201904
201905 201901 GROUPC JOINCO
------ ------
201905 201902
201905 201903
201905 201904
201905 201905
201906 201901
201906 201902
201906 201903
201906 201904
201906 201905
201906 201906
201907 201901 GROUPC JOINCO
------ ------
201907 201902
201907 201903
201907 201904
201907 201905
201907 201906
201907 201907
201908 201901
201908 201902
201908 201903
201908 201904
201908 201905 GROUPC JOINCO
------ ------
201908 201906
201908 201907
201908 201908 已选择 36 行。

  

3. 修改原来SQL中关于日期的不等值关联,可以起到走hash的作用。

关于Oracle中Sort Merge Join的改写的更多相关文章

  1. Oracle 三种连接方式 NESTED LOOP HASH JOIN SORT MERGE JOIN

    NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大( ...

  2. Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join

    关系数据库技术的精髓就是通过关系表进行规范化的数据存储,并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理. 表的三种关联方式: nested loop:从A表抽一条记录,遍历B表查找匹配 ...

  3. Nested loops、Hash join、Sort merge join(三种连接类型原理、使用要点)

    nested loop 嵌套循环(原理):oracle从较小结果集(驱动表.也可以被称为outer)中读取一行,然后和较大结果集(被侦查表,也可以叫做inner)中的所有数据逐条进行比较(也是等值连接 ...

  4. Sort merge join、Nested loops、Hash join(三种连接类型)

    目前为止,典型的连接类型有3种: Sort merge join(SMJ排序-合并连接):首先生产driving table需要的数据,然后对这些数据按照连接操作关联列进行排序:然后生产probed ...

  5. Nested Loop,Sort Merge Join,Hash Join

    三种连接工作方式比较: Nested loops 工作方式是从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops适用的场合是当一个关联表比较小的时候,效率会更高. Merg ...

  6. Nested Loops,Hash Join 和 Sort Merge Join. 三种不同连接的不同:

    原文:https://blog.csdn.net/tianlesoftware/article/details/5826546 Nested Loops,Hash Join 和 Sort Merge ...

  7. NESTED LOOPS & HASH JOIN & SORT MERGE JOIN

    表连接方式及使用场合 NESTED LOOP 对于被连接的数据子集较小的情况,nested loop连接是个较好的选择.nested loop就是扫描一个表,每读到一条记录,就根据索引去另一个表里面查 ...

  8. 三大表连接方式详解之Nested loop join和 Sort merge join

    在早期版本,Oracle提供的是nested-loop join,两表连接就相当于二重循环,假定两表分别有m行和n行       如果内循环是全表扫描,时间复杂度就是O(m*n)       如果内循 ...

  9. 排序合并连接(sort merge join)的原理

    排序合并连接(sort merge join)的原理 排序合并连接(sort merge join)的原理     排序合并连接(sort merge join)       访问次数:两张表都只会访 ...

随机推荐

  1. FZU 1876 JinYueTuan(排列组合)

    Description Let’s have a look at the picture below Now, do you know what it’s? Yeah , O(∩_∩)O~ , It ...

  2. MongoDB--副本集基本信息

    副本集的概念 副本集是一组服务器,其中有一个是主服务器(primary),用于处理客户端请求:还有多个备份服务器(secondary),用于保存主服务器的数据副本.如果主服务器崩溃了,备份服务器会自动 ...

  3. Mybatis基于SqlSession实现CRUD

    之前我们讲的基于XML还是接口注解配置都是使用接口实现CRUD,本文我们将要讲解通过splsession来实现CRUD,这种方法比较灵活. 基本配置 <!-- spring和MyBatis完美整 ...

  4. 大碗宽面Alpha第九周会议总结

    软件工程每周博客: 本周二我们进行了小组会议,对正在做的评课网站——海大优选进行了整体分析和明确分工.首先我们对整体网页进行了需求分析和框架分析,然后进行了分工,前端同学两人,后端同学两人,文档同学一 ...

  5. ubuntu下安装apidoc

    1.到http://nodejs.cn/download/下载nodejs 可以复制链接 使用wget下载更加快速 选择对应的操作系统位数 下载到/usr/local/src 此处强烈不建议编译安装 ...

  6. python 网络编程:socket(二)

    上节地址:Python网络编程:socket 一.send和sendall区别 send,sendall         ret = send('safagsgdsegsdgew') #send 发送 ...

  7. zabbix监控winserver网卡流量

    当前基于windows2008系统安装配置zabbix客户端,服务端为linux系统 1.设置防火墙规则 开启防火墙入站(tcp和udp)10050端口 2.在zabbix官网上下载windows包 ...

  8. 【数据库】一篇文章搞掂:MySQL数据库

    一.安装 使用版本:5.7(2018/08/03 阿里云的云数据库最高支持5.7,所以这里考虑用5.7) 下载版本:MySQL Community Server 5.7.23 下载地址:https:/ ...

  9. 20175223 《Java程序设计》第十一周学习总结

    目录 教材学习内容总结 代码调试中的问题和解决过程 1. Linux中编程实现计算器方法乘法报错,但 IDEA 中可以. [代码托管] 学习进度条 参考资料 目录 教材学习内容总结 因未熟练掌握第十章 ...

  10. thinkphp 连接postgresql

    PHP连接: php.ini中将extension=php_pgsql.dll前面的分号去掉extension=php_pdo_pgsql.dll前面的分号去掉,然后设置extension_dir指向 ...