在项目中,写的sql主要以查询为主,但是数据量一大,就会突出sql性能优化的重要性。其实在数据量2000W以内,可以考虑索引,但超过2000W了,就要考虑分库分表这些了。本文主要记录在实际项目中,一个需要查询很慢的sql的优化过程,如果有更好的方案,请在下面留言交流。

很多文章都有关于sql优化的方法,这里就不一一陈述了。如果有需要可以查看博客:https://blog.csdn.net/linhaiyun_ytdx/article/details/79101122

SELECT T.YHBH,
(SELECT NAME FROM DIM_REGION WHERE CODE = SUBSTR(T.GDDWBM, 0, 4)) GDDWMC,
(SELECT NAME FROM DIM_REGION WHERE CODE = T.GDDWBM) FJMC,
T.DFNY,
T.YHMC,
T.YDDZ,
(SELECT NAME FROM DIM_ELECTRICITY_TYPE WHERE CODE = T.YHLBDM) YDLBMC
FROM (SELECT DISTINCT T.YHBH,
DECODE(T.GDDWBM,
NULL,
'',
DECODE(T.GDDWBM, '', '', T.GDDWBM)) AS GDDWBM,
T.BBNY AS DFNY,
T.YHLBDM AS YHLBDM,
T.YHMC,
T2.YDDZ
FROM V_TEMP_TABLE_JHCBHSTJ_HISTORY T, TMP_KH_YDKH T2
WHERE T.YHBH = T2.YHBH(+)
AND NOT EXISTS (SELECT 1
FROM DJHJSL_LSB_FZ_HISTORY B
WHERE B.BBNY = T.BBNY
AND B.YHBH = T.YHBH
AND B.GDDWBM = T.GDDWBM
AND B.YHLBDM = T.YHLBDM
AND B.ZDCBZHS <> '')
) T
WHERE SUBSTR(T.GDDWBM, 0, 4) = ''
AND T.DFNY = ''

这个是我的sql脚本。其实这个脚本一点都不复杂。其中V_TEMP_TABLE_JHCBHSTJ_HISTORY,DJHJSL_LSB_FZ_HISTORY每个月增加330万,目前有1960多万, TMP_KH_YDKH表有330多万。DIM_REGION 和DIM_ELECTRICITY_TYPE 是两个数据字典项表。

在没有索引的情况下,这个脚本执行需要30s,看到执行过程,现在都是全表扫描的。接下来开始优化。

1.修改脚本的查询,将外层的查询条件放到里面,减少数据量。

SELECT T.YHBH,
(SELECT NAME FROM DIM_REGION WHERE CODE = SUBSTR(T.GDDWBM, 0, 4)) GDDWMC,
(SELECT NAME FROM DIM_REGION WHERE CODE = T.GDDWBM) FJMC,
T.DFNY,
T.YHMC,
T.YDDZ,
(SELECT NAME FROM DIM_ELECTRICITY_TYPE WHERE CODE = T.YHLBDM) YDLBMC
FROM (SELECT DISTINCT T.YHBH,
DECODE(T.GDDWBM,
NULL,
'',
DECODE(T.GDDWBM, '', '', T.GDDWBM)) AS GDDWBM,
T.BBNY AS DFNY,
T.YHLBDM AS YHLBDM,
T.YHMC,
T2.YDDZ
FROM V_TEMP_TABLE_JHCBHSTJ_HISTORY T, TMP_KH_YDKH T2
WHERE T.YHBH = T2.YHBH(+)
AND NOT EXISTS (SELECT 1
FROM DJHJSL_LSB_FZ_HISTORY B
WHERE B.BBNY = T.BBNY
AND B.YHBH = T.YHBH
AND B.GDDWBM = T.GDDWBM
AND B.YHLBDM = T.YHLBDM
AND B.ZDCBZHS <> '')
AND SUBSTR(T.GDDWBM, 0, 4) = ''
AND T.BBNY = ''
) T

2.对三个表都建上索引

对V_TEMP_TABLE_JHCBHSTJ_HISTORY根据DFNY,SUBSTR(T.GDDWBM, 0, 4)建上联合索引。

CREATE INDEX IDX_TMP_JHCBHSTJ_HISTORY_UNION ON V_TEMP_TABLE_JHCBHSTJ_HISTORY(BBNY,SUBSTR(GDDWBM, 0, 4));

对TMP_KH_YDKH表,使用了关联,所以需要对yhbh建个索引

create index IDX_YHBH_KH on TMP_KH_YDKH (YHBH);

对于DJHJSL_LSB_FZ_HISTORY表,在not EXISTS里面,会全表扫描这个表,现在对他建立联合索引试试。

CREATE INDEX IDX_DJHJSL_FZ_HISTORY_UNION ON V_TEMP_TABLE_JHCBHSTJ_HISTORY(BBNY,YHBH,GDDWBM,YHLBDM);

查看oracle的执行计划,建立联合索引,并没有让这个表走索引,还是在全表扫描的,但是查询已经提升到9s了。

接下来对分别对这四个字段建立索引:

create index IDX_DJHJSL_FZ_HISTORY_BBNY on DJHJSL_LSB_FZ_HISTORY (BBNY);
create index IDX_DJHJSL_FZ_HISTORY_YHBH on DJHJSL_LSB_FZ_HISTORY (YHBH);
create index IDX_DJHJSL_FZ_HISTORY_GDDWBM on DJHJSL_LSB_FZ_HISTORY (GDDWBM);
create index IDX_DJHJSL_FZ_HISTORY_YHLBDM on DJHJSL_LSB_FZ_HISTORY (YHLBDM);

从执行计划来看,oracle只走了IDX_DJHJSL_FZ_HISTORY_BBNY这个索引,现在最快已经到1.95s了。

虽然现在已经满足了查询3s内的要求,但是考虑到以后,每个月的数据增长,数据量有5000万,一亿这样的大数据量的时候还是会很慢。

其实我在正式环境测试的时候,NOT EXISTS 里面的这个表,建立单个索引是没有用的,建立联合索引才会使这个表走索引,可能是因为电脑的cpu不同等因素影响的。

上面的优化方法当然不能满足项目的需求,接下来结合业务进行优化。作为一个监控系统,数据是T+1的,不需要追求实时性,这些数据,都是使用etl抽取工具每天定时抽取的。而且每个月300万数据,用户只关注的只有几千条。所以结合业务,我们在使用etl抽取完数据后,将用户关注的数据插入到另一张表中,这样,每个月只有几千条数据,这样的话,一年也才几万条数据,对oracle来说决定是零压力的。

-----------------------------------------------------我是分界线---------------------------------------------------------

2020年5月1日更新:前一天我有点空闲时间,想起来对这个sql再做一次优化(经过几个月的增长,已经有了4000万的数据,就算上面的那个脚本查询还有有点慢),因为我们的表数据是按月插入的,客户查询也是按月查询的,所以我就对 V_TEMP_TABLE_JHCBHSTJ_HISTORY,DJHJSL_LSB_FZ_HISTORY 这两个月进行了按月分区(列表分区)。

下面是执行脚本(我这里没有建默认分区,在项目中一定要建立默认分区):

-- Create table 分母
create TABLE JHCBHSTJ_HISTORY1
(
BBNY VARCHAR2(6),
BBNYR VARCHAR2(8),
GDDWBM VARCHAR2(20),
YHLBDM VARCHAR2(20),
DYLBBM VARCHAR2(20),
YHBH VARCHAR2(50),
YHMC VARCHAR2(200),
DYJHCBKHS NUMBER(10)
)
partition by LIST(BBNY)
(
partition P_JHCBHSTJ_HISTORY_201905 values (''),
partition P_JHCBHSTJ_HISTORY_201906 values (''),
partition P_JHCBHSTJ_HISTORY_201907 values (''),
partition P_JHCBHSTJ_HISTORY_201908 values (''),
partition P_JHCBHSTJ_HISTORY_201909 values (''),
partition P_JHCBHSTJ_HISTORY_201910 values (''),
partition P_JHCBHSTJ_HISTORY_201911 values (''),
partition P_JHCBHSTJ_HISTORY_201912 values (''), partition P_JHCBHSTJ_HISTORY_202001 values (''),
partition P_JHCBHSTJ_HISTORY_202002 values (''),
partition P_JHCBHSTJ_HISTORY_202003 values (''),
partition P_JHCBHSTJ_HISTORY_202004 values (''),
partition P_JHCBHSTJ_HISTORY_202005 values (''),
partition P_JHCBHSTJ_HISTORY_202006 values (''),
partition P_JHCBHSTJ_HISTORY_202007 values (''),
partition P_JHCBHSTJ_HISTORY_202008 values (''),
partition P_JHCBHSTJ_HISTORY_202009 values (''),
partition P_JHCBHSTJ_HISTORY_202010 values (''),
partition P_JHCBHSTJ_HISTORY_202011 values (''),
partition P_JHCBHSTJ_HISTORY_202012 values (''), partition P_JHCBHSTJ_HISTORY_202101 values (''),
partition P_JHCBHSTJ_HISTORY_202102 values (''),
partition P_JHCBHSTJ_HISTORY_202103 values (''),
partition P_JHCBHSTJ_HISTORY_202104 values (''),
partition P_JHCBHSTJ_HISTORY_202105 values (''),
partition P_JHCBHSTJ_HISTORY_202106 values (''),
partition P_JHCBHSTJ_HISTORY_202107 values (''),
partition P_JHCBHSTJ_HISTORY_202108 values (''),
partition P_JHCBHSTJ_HISTORY_202109 values (''),
partition P_JHCBHSTJ_HISTORY_202110 values (''),
partition P_JHCBHSTJ_HISTORY_202111 values (''),
partition P_JHCBHSTJ_HISTORY_202112 values ('')
);; ALTER SESSION ENABLE PARALLEL DML;
--插入数据 (采用并发,依据服务器性能和核数而定)
INSERT /*+PARALLEL(JHCBHSTJ_HISTORY1,30)*/ INTO JHCBHSTJ_HISTORY1
SELECT /*+PARALLEL(V_TEMP_TABLE_JHCBHSTJ_HISTORY,30)*/ * FROM V_TEMP_TABLE_JHCBHSTJ_HISTORY; COMMIT; --替换之前的表
RENAME V_TEMP_TABLE_JHCBHSTJ_HISTORY TO JHCBHSTJ_HISTORY_BAK;
RENAME JHCBHSTJ_HISTORY1 TO V_TEMP_TABLE_JHCBHSTJ_HISTORY;
-- Create table  分子
create table DJHJSL_LSB_FZ_HISTORY_1
(
BBNY VARCHAR2(6),
BBNYR VARCHAR2(8),
GDDWBM VARCHAR2(20),
YHLBDM VARCHAR2(20),
DYLBBM VARCHAR2(20),
YHBH VARCHAR2(50),
YHMC VARCHAR2(200),
ZDCBZHS NUMBER(10)
)
partition by LIST(BBNY)
(
partition P_DJHJSL_LSB_FZ_HISTORY_201905 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201906 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201907 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201908 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201909 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201910 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201911 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_201912 values (''), partition P_DJHJSL_LSB_FZ_HISTORY_202001 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202002 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202003 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202004 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202005 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202006 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202007 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202008 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202009 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202010 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202011 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202012 values (''), partition P_DJHJSL_LSB_FZ_HISTORY_202101 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202102 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202103 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202104 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202105 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202106 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202107 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202108 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202109 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202110 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202111 values (''),
partition P_DJHJSL_LSB_FZ_HISTORY_202112 values ('')
);; ALTER SESSION ENABLE PARALLEL DML;
--插入数据 (采用并发,依据服务器性能和核数而定)
INSERT /*+PARALLEL(DJHJSL_LSB_FZ_HISTORY_1,30)*/ INTO DJHJSL_LSB_FZ_HISTORY_1
SELECT /*+PARALLEL(DJHJSL_LSB_FZ_HISTORY,30)*/ * FROM DJHJSL_LSB_FZ_HISTORY; COMMIT; -- Create/Recreate indexes
create index IDX_DJHJSL_FZ_HISTORY_UNION1 on DJHJSL_LSB_FZ_HISTORY_1 (BBNY, YHBH, GDDWBM, YHLBDM); --替换之前的表
RENAME DJHJSL_LSB_FZ_HISTORY TO DJHJSL_LSB_FZ_HISTORY_bak;
RENAME DJHJSL_LSB_FZ_HISTORY_1 TO DJHJSL_LSB_FZ_HISTORY;

同时在两个表插入完成之后,对两个表收集了执行信息:

--收集执行信息
EXEC DBMS_STATS.gather_table_stats(user,'V_TEMP_TABLE_JHCBHSTJ_HISTORY',cascade=>true); --收集执行信息
EXEC DBMS_STATS.gather_table_stats(user,'DJHJSL_LSB_FZ_HISTORY',cascade=>true);

这样我在执行查询的时候,下面的图可以看到效果,性能提升还是很大的。

如果大家还有其他的方式优化,请在下方留言交流。

oracle性能优化(项目中的一个sql优化的简单记录)的更多相关文章

  1. 项目中常用的MySQL 优化

    本文我们来谈谈项目中常用的MySQL优化方法,共19条,具体如下: 一.EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看SQL执行计划. 下面来个简单的示例,标注(1.2.3.4.5)我 ...

  2. Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作

    Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作 1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(Studen ...

  3. 【Filter 不登陆无法访问】web项目中写一个过滤器实现用户不登陆,直接给链接,无法进入页面的功能

    在web项目中写一个过滤器实现用户不登陆,直接给链接,无法进入页面,而重定向到登陆界面的功能. 项目是用springMVC+spring+hibernate实现 (和这个没有多大关系) 第一步: 首先 ...

  4. 项目中的一个分页功能pagination

    项目中的一个分页功能pagination <script> //总页数 ; ; //分页总数量 $(function () { // $("#pagination"). ...

  5. 如何在 GitHub 的项目中创建一个分支呢?

    如何在 GitHub 的项目中创建一个分支呢? 其实很简单啦,直接点击 Branch,然后在弹出的文本框中添加自己的 Branch Name 然后点击蓝色的Create branch就可以了,这样一来 ...

  6. Java项目中每一个类都可以有一个main方法

    Java项目中每一个类都可以有一个main方法,但只有一个main方法会被执行,其他main方法可以对类进行单元测试. public class StaticTest { public static ...

  7. Spring+SpringMVC+MyBatis+easyUI整合优化篇(十二)数据层优化-explain关键字及慢sql优化

    本文提要 从编码角度来优化数据层的话,我首先会去查一下项目中运行的sql语句,定位到瓶颈是否出现在这里,首先去优化sql语句,而慢sql就是其中的主要优化对象,对于慢sql,顾名思义就是花费较多执行时 ...

  8. oracle定时器在项目中的应用

    业务需求: 现在业务人员提出了一个需求: 在项目中的工作流,都要有一个流程编号,此编号有一定的规则: 前四五位是流程的字母缩写,中间是8位的日期,后面五位是流水码,要求流水码每天从00001开始.即: ...

  9. Javaweb项目中出现java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone.异常

    javaweb项目中java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represent ...

随机推荐

  1. 感觉async await 异步编程 并不能提升性能?

    我有2个方法 代码相同 都是执行上传文件IO操作 一个同步 一个异步 接着我用POSTMAN 分别用200个线程 去同时测试2个接口 结果很意外 2个接口 同时执行完成的速度 异步更慢 之前经常看别人 ...

  2. Prometheus 自动发现

    目录 简介 环境说明 静态配置 重新加载配置文件 基于文件发现配置 重新加载配置文件 添加主机测试 基于DNS的A记录 修改配置文件 重新加载配置文件 基于DNS的SRV记录自动发现 修改配置文件 重 ...

  3. 03-kubernetes 应用快速入门

    目录 增删改查 增 service创建 测试其他pod通过series访问nginx 测试手动变更nginx对应的pod的ip pod和service之间的关系 service调度测试 创建myapp ...

  4. python初识-环境搭建,变量,条件,循环语句

    1.python环境搭建: (1)安装Anaconda ,可选择非C盘安装: 注意:都勾选: (2)安装Pycharm 默认安装即可,安装过程同样都勾选: (3)破解Pycharm https://w ...

  5. javascript基础修炼(13)——记一道有趣的JS脑洞练习题【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  6. 三伏天里小试牛刀andriod 开发 #华为云·寻找黑马程序员#

    2019年07月,北京,三伏天,好热啊.越热自己还越懒得动换(肉身给的信号),但是做为产品经理/交互设计师的,总想着思考些什么(灵魂上给的信号),或者是学习些什么,更有利于将来的职业发展吧,哈哈哈.工 ...

  7. 新一代数据安全的制胜法宝-UBA

    [摘要]在入侵防御领域,运用数据分析的方法保护数据的技术其实没有什么新的东西,比如防火墙-分析数据包的内容以及其他的元数据,如IP地址,从增长的数据条目中检测和阻断攻击者:防病毒软件不断的扫描文件系统 ...

  8. plsql判断和循环

    if语句 语法1 如果条件成立,执行if和end if 之间的语句. if 条件表达式 then plsql语句; end if; 语法2 if 条件表达式 then 条件成立时执行的语句; else ...

  9. Swoole高效跟传统的web开发有什么区别?

    一.swoole的运行模式 Swoole高效跟传统的web开发有什么区别,除了传统的LAMP/LNMP同步开发模式,swoole的异步开发模式是怎么样的. 1.1.传统web开发模式 PHP web开 ...

  10. javascript数据类型和类型转换

    一  数据类型 1)typeof 查看数据类型 1.number 数字 取值范围:正无穷 - 负无穷.NaN 正无穷:Number.POSITIVE_INFINITY 负无穷:Number.NEGAT ...