陆老师好久没找我,今天他在营运商遇到2条性能慢的SQL,说找了好多专家老手看了都优化不了,然后就找到我打算给我玩玩。

第一次接触营运商行业的SQL,妈呦还真的复杂

 SQL1:

SELECT WORK_ORDER_ID        as workOrderId,
WORK_ITEM_ID as workItemId,
TRACE_ID as traceID,
TOTAL_DATE as totalDate,
SEND_TIME as sendTime,
SEND_STATUS as sendStatus,
REQUEST_TIME as requestTime,
REMARKS as remarks,
PROVINCE as province,
PRIORITY as priority,
nvl(PHONE_NO, '0') as phoneNo,
PARENTCALLID as parentcallid,
OTHER_CHAR2 as otherChar2,
OTHER_CHAR1 as otherChar1,
OTHER_CHAR as otherChar,
OSS_ORDER_ID as ossOrderId,
nvl(ORDER_TYPE, '0') as orderType,
ORDER_CREATE_TIME as orderCreateTime,
OP_TIME as opTime,
OP_CODE as opCode,
nvl(MOD_VALUE, '0') as modValue,
nvl(LOGIN_NO, '0') as loginNo,
IOM_RECEIVE_TIME as iomReceiveTime,
IOM_COMPLETE_TIME as iomCompleteTime,
nvl(IMSI_NO, '0') as imsiNo,
ID_NO as idNo,
HLR_CODE as hlrCode,
GROUP_ID as groupId,
CRM_ORDER_ID as crmOrderId,
COMMAND_ID as commandId,
COMMAND_COUNT as commandCount,
COMMAND_CODE as commandCode,
CMS_RECEIVE_TIME as cmsReceiveTime,
CMS_COMPLETE_TIME as cmsCompleteTime,
ACK_TIME as ackTime,
ACK_INFO as ackInfo,
ACK_CODE as ackCode
FROM px_lu
WHERE send_status = '0'
and mod(to_number(trim(phone_no)), 1) = 0
ORDER BY request_time, command_id limit 500;
执行时间:500 rows in set (0.853 sec)

这条分页SQL在 ORACLE 上 30ms 就可以跑出来,在 GoldenDB 要跑近 1s 才能出结果。

 SQL索引优化:

create index idx_1_2_3 on px_lu (send_status,request_time, command_id );
500 rows in set (0.013 sec)

索引加上以后 0.013 s 就可以跑出结果,非常简单。

 SQL2:

select new_busi_code,
new_status_cd,
table_name,
new_group_id,
count(1) count
from (select (select nvl((select x.rule_value
from vccccx t,
frtgh x
where t.rule_code = '1000000048'
and t.busi_rule_code = x.busi_rule_code
and t.busi_code = a.busi_code), decode(busi_level, '2', par_busi_code, BUSI_CODE))
from sffsss
where busi_code = a.busi_code) as new_busi_code,
(nvl((select x.rule_value
from vccccx t,
frtgh x
where t.rule_code = '1000000046'
and t.busi_rule_code = x.busi_rule_code
and t.busi_code = a.busi_code), 's')) new_status_cd,
(select op_note as table_name
from swbbbbbb
where maindata_code = 'RS-NO-0001'
and maindata_value = (nvl((select x.rule_value
from vccccx t,
frtgh x
where t.rule_code = '1000000046'
and t.busi_rule_code = x.busi_rule_code
and t.busi_code = a.busi_code), 's'))) table_name,
nvl((select parent_group_id
from dsdsd
where group_id = a.group_id
and parent_level = nvl((select x.rule_value
from vccccx t,
frtgh x
where t.rule_code = '1000000047'
and t.busi_rule_code = x.busi_rule_code
and t.busi_code = a.busi_code), 3)), a.group_id) as new_group_id
from dsdsd b,
rsrsrs a
WHERE b.group_id = a.group_id
AND a.status_cd in ('2', 'y')
AND b.parent_group_id = '14'
and a.region_code = '2201'
and a.tenant_id = '22'
and b.tenant_id = '22'
AND a.rec_Time <= to_date(TO_CHAR(SYSDATE, 'YYYYMMDD') || ' 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
where new_busi_code is not null
and new_status_cd is not null
and new_group_id is not null
group by new_busi_code, new_status_cd, table_name, new_group_id;
10 rows in set (9 min 46.240 sec)

这条SQL的表连接关系是真的超级复杂,来在ORACLE上跑30s可以出结果,在GoldenDB 却快跑10分钟才能出结果。

其实主要就是慢在标量子查询,只要改写成左连接性能就可以提升上来,里面的逻辑真的是太复杂了,花了不少时间搞清关系,营运商SQL的复杂程度总算见到了。

 SQL2等价改写:

select new_busi_code,
new_status_cd,
table_name,
new_group_id,
count(1) count
from (
  SELECT COALESCE(rv1.rule_value, DECODE(cb.busi_level, '2', cb.par_busi_code, cb.BUSI_CODE)) AS new_busi_code,
COALESCE(rv2.rule_value, 's') AS new_status_cd,
mv.op_note AS table_name,
COALESCE(cgr.parent_group_id, a.group_id) AS new_group_id
FROM rsrsrs a
LEFT JOIN dsdsd b ON b.group_id = a.group_id
LEFT JOIN sffsss cb ON cb.busi_code = a.busi_code
LEFT JOIN vccccx br1 ON br1.busi_code = a.busi_code AND br1.rule_code = '1000000048'
LEFT JOIN frtgh rv1 ON br1.busi_rule_code = rv1.busi_rule_code
LEFT JOIN vccccx br2 ON br2.busi_code = a.busi_code AND br2.rule_code = '1000000046'
LEFT JOIN frtgh rv2 ON br2.busi_rule_code = rv2.busi_rule_code
LEFT JOIN swbbbbbb mv
ON mv.maindata_value = COALESCE(rv2.rule_value, 's') AND mv.maindata_code = 'RS-NO-0001'
LEFT JOIN vccccx br3 ON br3.busi_code = a.busi_code AND br3.rule_code = '1000000047'
LEFT JOIN frtgh rv3 ON br3.busi_rule_code = rv3.busi_rule_code
LEFT JOIN dsdsd cgr ON cgr.group_id = a.group_id AND cgr.parent_level = COALESCE(rv3.rule_value, 3)
WHERE a.status_cd IN ('2', 'y')
AND b.parent_group_id = '14'
AND a.region_code = '2201'
AND a.tenant_id = '22'
AND b.tenant_id = '22'
AND a.rec_Time <= to_date(TO_CHAR(SYSDATE, 'YYYYMMDD') || ' 00:00:00', 'yyyy-mm-dd hh24:mi:ss')
AND COALESCE(rv1.rule_value, DECODE(cb.busi_level, '2', cb.par_busi_code, cb.BUSI_CODE)) IS NOT NULL
AND COALESCE(rv2.rule_value, 's') IS NOT NULL
AND COALESCE(cgr.parent_group_id, a.group_id) IS NOT NULL
)
where new_busi_code is not null
and new_status_cd is not null
and new_group_id is not null
group by new_busi_code, new_status_cd, table_name, new_group_id;
10 rows in set (3 min 12.370 sec)

改写完以后运行速度从9分钟可以降到3分钟左右就能出结果,依然是很慢,还有继续优化空间。

 SQL2创建索引继续优化:

create index idx_1_2_3          ON rsrsrs(group_id,busi_code, status_cd, region_code, tenant_id, rec_Time);
create index idx_4_5_6 ON dsdsd(group_id, parent_group_id, tenant_id);
create index idx_7_8_9 ON sffsss(busi_code);
create index idx_11_12_13 ON vccccx(busi_code, rule_code, busi_rule_code);
create index idx_14_15_16 ON frtgh(busi_rule_code);
create index idx_17_18_19 ON swbbbbbb(maindata_value, maindata_code);
10 rows in set (48.876 sec)

最终通过等价改写 + 索引优化手段,SQL2从9分钟左右的执行时间降到48秒就可以出结果,基本没有继续优化的空间了。

中兴GoldenDB(MYSQL)营运商SQL优化案例(超复杂SQL)的更多相关文章

  1. mysql的sql优化案例

    前言 mysql的sql优化器比较弱,选择执行计划貌似很随机. 案例 一.表结构说明mysql> show create table table_order\G***************** ...

  2. SQL优化案例—— RowNumber分页

    将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术. 下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明. 先来看看我们最常见的分页的样子: WITH CTE AS ...

  3. SQL 优化案例 1

    create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...

  4. SQL 优化案例

    create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...

  5. SQL优化的一些总结 SQL编写一般要求

    SQL编写一般要求---SQL语句尽可能简单---分解联接保证高并发---同数据类型的列值比较---不在索引列做运算---禁止使用SELECT *---避免负向查询和%前缀模糊查询---保持事务(连接 ...

  6. 智能SQL优化工具--SQL Optimizer for SQL Server(帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 )

    SQL Optimizer for SQL Server 帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 SQL Optimizer for SQL Server 让 SQL Serve ...

  7. Oracle之SQL优化专题01-查看SQL执行计划的方法

    在我2014年总结的"SQL Tuning 基础概述"中,其实已经介绍了一些查看SQL执行计划的方法,但是不够系统和全面,所以本次SQL优化专题,就首先要系统的介绍一下查看SQL执 ...

  8. Oracle之SQL优化专题02-稳固SQL执行计划的方法

    首先构建一个简单的测试用例来实际演示: create table emp as select * from scott.emp; create table dept as select * from ...

  9. 数栈SQL优化案例:隐式转换

    MySQL是当下最流行的关系型数据库之一,互联网高速发展的今天,MySQL数据库在电商.金融等诸多行业的生产系统中被广泛使用. 在实际的开发运维过程中,想必大家也常常会碰到慢SQL的困扰.一条性能不好 ...

  10. Mysql大范围分页优化案例

    在BBS线上业务抓到如下分页SQL: meizu_bbs meizu_bbs Query Sending data , meizu_bbs meizu_bbs Query Sending data , ...

随机推荐

  1. 【渗透测试】Cobalt Strike制作钓鱼邮件渗透Windows

    目标 在kali中使用Cobalt Strike制作钓鱼邮件,对Windows进行渗透 机器环境 kali(服务端):192.168.175.129 win11(攻击机):192.168.175.12 ...

  2. Windows商店开发者注册失败

    前言 最近写了个小工具想上架Windows应用商店,但是在填写信息那一页总是失败,提示Error code 2201. Correlation ID 9d436e3a-94df-498a-b224-8 ...

  3. pssh 安装使用

    which python # 查看python 是否指向 python2 ll /usr/bin/python # lrwxrwxrwx. 1 root root 7 2020-03-24 03:08 ...

  4. Spring Boot 最佳实践

    本文翻译自国外论坛 medium,原文地址:https://medium.com/@raviyasas/spring-boot-best-practices-for-developers-3f3bdf ...

  5. Unity的IPreprocessComputeShaders:深入解析与实用案例

    Unity IPreprocessComputeShaders Unity IPreprocessComputeShaders是Unity引擎中的一个非常有用的功能,它可以让开发者编译Compute ...

  6. python将print的打印内容保存到日志

    将python程序中的所有打印内容都输出到日志文件中,在程序执行完成后,方便查询程序运行过程是否出现异常. 1. 将打印内容输出到日志文件 1.1 代码实现: sys.stdout = open('s ...

  7. Mybatis框架的搭建和基本使用

    本文总结最原始Mybatis框架的搭建和最基本使用(不涉及Spring框架体系). 1 依赖 首先,我们要引入Mybatis依赖: <dependency> <groupId> ...

  8. linux cat查看文件使用grep实现多条件多场景过滤

    转载请注明出处: 在实际应用过程中,我们查看日志文件时,经常会根据一定自定义的词语过滤,查看所有相关的数据行.最近遇到用cat查看文件,需要根据多关键词进行不同的场景过滤,在这里进行一个简单的总结: ...

  9. 如何正确实现一个自定义 Exception

    最近在公司的项目中,编写了几个自定义的 Exception 类.提交 PR 的时候,sonarqube 提示这几个自定义异常不符合 ISerializable patten. 花了点时间稍微研究了一下 ...

  10. 电气工程师必学------CODESYS v3.5 入门学习笔记(一)

    一.新建工程 打开软件新建工程,如图 此教程只是入门练习,所以这里一般情况下都是创建的Standard project,也就是标准工程.窗口下方可以设置工程名称与存放位置. 紧接着是选择设备与编译语言 ...