<Oracle优化新常态>第一章
《Oracle优化新常态》第二章强拆(1)
《Oracle优化新常态》第二章强拆(2)
<Oracle优化新常态> 第三章 三大配置
<Oracle优化新常态>第四章 分库分表
<Oracle优化新常态> 第五章 急诊法
SQL是应用程序发给数据库工作的基本单位!所以优化SQL是优化的重中之重。也是立杆见影,成效快,短平快,易出GDP成绩的。但是SQL优化又是个深奥,高深的技术,要充分理解数据库运行机制,也要了解业务特性,以及PL/SQL开发技术。是业务+开发+原理的三位一体!不是一般运维DBA能胜能的,不是会搭建个数据库,搭建个高可用DATAGUARD,搭建个集群RAC,搭建个数据同步OGG的运维DBA就可以优化的。也不是运维工程师能胜能的,虽然你会索引大法。如今SQL是有开发人员写的,自然他们写得好才叫奇迹,写得很垃圾那叫做正常。开发人员工作业绩就是出GDP,而不是出性能。他们连代码质量都无法保证,都要交给测试人员去完成,而且测试人员的数量都是开发人员的两倍。至于性能我就呵呵了! 你说对开发人员做培训,呵呵! 说深了他们又不懂,说潜了他们傲娇觉得鄙视你!
那我就说简单易用易懂而且见效快的SQL优化大法!
第一 优化大法 美图秀秀法
只要是个女人拍照照,必然要美化下自己,PS下自己,何况是个男人啊。所以作为男人写的SQL,也是要爱护自己的面子的,如今大男人主义盛行的年代,虽然IT男字写不好,可代码敲得也要漂亮的喊不要 不要啊!
其一 一段赏心悦目的SQL代码,会给人一种心情愉悦之感。
其二 可以很快判断出语法问题
其三 可以很快地了解到SQL性能问题所在
其四 见过丑的你才知道什么是美好的
SELECT GW.GW_NO, GW.GW_MER_NO, GW.GW_STATUS, (SELECT COUNT(1) FROM CCPS_TRADERECORD C WHERE C.TR_STATUS = 1 AND C.TR_DATETIME >= TO_DATE(:1, 'yyyy-mm-dd') AND C.TR_DATETIME <TO_DATE(:2, 'yyyy-mm-dd') AND GW.GW_NO = C.TR_GW_NO AND gw.gw_mer_no = c.tr_mer_no AND C.TR_CARDTYPE = :3 ) AS LAST_COUNT, (SELECT COUNT(1) FROM CCPS_TRADERECORD D WHERE D.TR_STATUS = 1 AND D.TR_DATETIME >= TO_DATE(:4, 'yyyy-mm-dd') AND D.TR_DATETIME < TO_DATE(:5, 'yyyy-mm-dd') AND GW.GW_NO = D.TR_GW_NO AND gw.gw_mer_no =
d.tr_mer_no AND D.TR_CARDTYPE = :6 ) TOTAL_CNT, (SELECT COUNT(DISTINCT UN.UP_TR_NO) FROM CCPS_UNNORMAL_PROCESS UN INNER JOIN CCPS_TRADERECORD UT ON UT.TR_NO = UN.UP_TR_NO WHERE UN.UP_CPD_TIME >= TO_DATE(:7, 'yyyy-mm-dd') AND UN.UP_CPD_TIME < TO_DATE(:8, 'yyyy-mm-dd') AND UN.UP_TYPE IN (2, 6) AND UT.TR_CARDTYPE = :9 AND GW.GW_NO = UT.TR_GW_NO AND GW.GW_MER_NO = UT.Tr_Mer_No ) PROTEST_CNT FROM CCPS_GATEWAY GW WHERE GW.GW_STATUS IN (-1, 1)
用PL/SQL格式化工具后这样
SELECT GW.GW_NO,
GW.GW_MER_NO,
GW.GW_STATUS,
(SELECT COUNT(1)
FROM CCPS_TRADERECORD C
WHERE C.TR_STATUS = 1
AND C.TR_DATETIME >= TO_DATE(:1, 'yyyy-mm-dd')
AND C.TR_DATETIME < TO_DATE(:2, 'yyyy-mm-dd')
AND GW.GW_NO = C.TR_GW_NO
AND gw.gw_mer_no = c.tr_mer_no
AND C.TR_CARDTYPE = :3) AS LAST_COUNT,
(SELECT COUNT(1)
FROM CCPS_TRADERECORD D
WHERE D.TR_STATUS = 1
AND D.TR_DATETIME >= TO_DATE(:4, 'yyyy-mm-dd')
AND D.TR_DATETIME < TO_DATE(:5, 'yyyy-mm-dd')
AND GW.GW_NO = D.TR_GW_NO
AND gw.gw_mer_no = d.tr_mer_no
AND D.TR_CARDTYPE = :6) TOTAL_CNT,
(SELECT COUNT(DISTINCT UN.UP_TR_NO)
FROM CCPS_UNNORMAL_PROCESS UN
INNER JOIN CCPS_TRADERECORD UT
ON UT.TR_NO = UN.UP_TR_NO
WHERE UN.UP_CPD_TIME >= TO_DATE(:7, 'yyyy-mm-dd')
AND UN.UP_CPD_TIME < TO_DATE(:8, 'yyyy-mm-dd')
AND UN.UP_TYPE IN (2, 6)
AND UT.TR_CARDTYPE = :9
AND GW.GW_NO = UT.TR_GW_NO
AND GW.GW_MER_NO = UT.Tr_Mer_No) PROTEST_CNT
FROM CCPS_GATEWAY GW
WHERE GW.GW_STATUS IN (-1, 1)
当还是不漂亮,只是不丑了而已,人工化妆下。
SELECT GW.GW_NO,
GW.GW_MER_NO,
GW.GW_STATUS,
(
SELECT COUNT(1)
FROM CCPS_TRADERECORD C
WHERE C.TR_STATUS = 1
AND C.TR_DATETIME >= TO_DATE(:1, 'yyyy-mm-dd')
AND C.TR_DATETIME < TO_DATE(:2, 'yyyy-mm-dd')
AND GW.GW_NO = C.TR_GW_NO
AND gw.gw_mer_no = c.tr_mer_no
AND C.TR_CARDTYPE = :3
) AS LAST_COUNT,
(
SELECT COUNT(1)
FROM CCPS_TRADERECORD D
WHERE D.TR_STATUS = 1
AND D.TR_DATETIME >= TO_DATE(:4, 'yyyy-mm-dd')
AND D.TR_DATETIME < TO_DATE(:5, 'yyyy-mm-dd')
AND GW.GW_NO = D.TR_GW_NO
AND gw.gw_mer_no = d.tr_mer_no
AND D.TR_CARDTYPE = :6
) TOTAL_CNT,
(
SELECT COUNT(DISTINCT UN.UP_TR_NO)
FROM CCPS_UNNORMAL_PROCESS UN
INNER JOIN CCPS_TRADERECORD UT ON UT.TR_NO = UN.UP_TR_NO
WHERE UN.UP_CPD_TIME >= TO_DATE(:7, 'yyyy-mm-dd')
AND UN.UP_CPD_TIME < TO_DATE(:8, 'yyyy-mm-dd')
AND UN.UP_TYPE IN (2, 6)
AND UT.TR_CARDTYPE = :9
AND GW.GW_NO = UT.TR_GW_NO
AND GW.GW_MER_NO = UT.Tr_Mer_No
) PROTEST_CNT
FROM CCPS_GATEWAY GW
WHERE GW.GW_STATUS IN (-1, 1);
再来个丑的
select name,
value,
unit,
(case
when unit = 'bytes' then
(value / 1024 / 1024 / 1024)
else
NULL
end) as UNIT_GB
from V $PGASTAT;
select name,
value,
unit,
case when unit = 'bytes' then (value/1024/1024/1024, 3) else NULL end as UNIT_GB
from V $PGASTAT;
人工美化原则:
1 select 字段 如果存在计算字段的话,或者对字段额外处理,则每个字段占一行
2 SQL 列长度由原来的80列改成120列,毕竟如今都是宽屏时代了
3 子查询的小挂号单独占一行,以显示出这里有个子查询
4 CASE 一般都是处理SELECT字段的,不能分成多行,必须独占一行,拥挤在一起,因为它们是个逻辑整体,拆多行,大脑无法把上下连在一起。
5 小挂号不要乱用,如上 CASE 前面加个小挂号 (case... ) as 小挂号是提高内部的运算优先级的。加不加小挂号都无法改变的优先级,那就不要加,会干扰视觉。
6 关键字都要右对齐
7 SQL语句应该小写,大写无法快速区分单词
8 请使用新的表连接法 inner join left join
9 inner join on x.id=y.id on与join 同在一行
10 FROM 后跟的是主表,紧接着是inner join 表,然后是 left join 最后是其他的
11 select 每个字段最好前面有表名前缀
12 尊重习惯把条件字段左边放 and (sysdate - :2 / (24 * 60)) >= trd.tr_datetime
select a.id,a.name,b.sex,b.btherday,c.country,c.address,d.email
from a
inner join b on a.id=b.id
left join c on a.id=c.id
right join d on a.id=d.id
where 1=1
and a.name='shark'
第二优化大法 条件字段不处理法
所谓条件字段不处理法 是说不对WHERE 后面的字段做任何处理。
select trd.tr_no,
trd.tr_reference,
trd.tr_status,
trd.tr_paystarttime,
trd.tr_datetime,
trd.tr_bankcurrency,
trd.tr_bankamout,
trd.tr_cha_code,
ch.cha_merno,
ch.cha_vpc_accesscode,
ch.cha_secure_secret,
trd.TR_SF_DATA,
trd.TR_CARDTYPE
from ccps_traderecord trd
left join ccps_channel ch on trd.tr_cha_code = ch.cha_code
where trd.TR_MER_NO != :1
and trd.tr_checked = 0
and trd.tr_status != -2
and (sysdate - :2 / (24 * 60)) >= trd.tr_datetime
and upper(trd.tr_bank_code) = :3
and rownum <= :4
order by trd.tr_id asc
这语句的绿色部分对字段做了UPDATE处理。任务对字段做处理都无法利用上该字段的索引。
第三优化大法 隐身大法
所谓隐身 是指默认的优先级 比如字符和日期之间的转换
and a.name=12360
name 是字符类型的字段,而输入的是数字,默认情况下会对name做隐身转换。
第四优化大法 吸星大法
吸星 是指 星号 *
一般情况下 大家都喜欢 select from a 很省事 快捷,开发人员的最爱。至于会导致什么后果? 我就不说了,select 你真的需要全部字段吗? 或许你说是! 再问你 你需要这个表将来添加的字段吗? 哦 这个就不晓得了 那麻烦你 把你需要的字段一 一 写出来 好不?
星号确实很便利,当不是这样用的,星号必须远离真实表
如下星号远离 真实表
select *
from
(
select f.*,rownum as rn
from
(
select a.id,a.name,b.sex,b.btherday,c.country,c.address,d.email
from a
inner join b on a.id=b.id
left join c on a.id=c.id
right join d on a.id=d.id
where 1=1
and a.name='shark'
order by a.name desc
) f
)
where rn <=10
第五优化大法 绑定变量法
此法只适应于 OLTP 和OLQP两种请求类型
所谓的绑定变量,也就是开发人员常见的参数,定义个形参,真实运行的时候传递个实参。如下 JAVA一般是问号
select a.id,a.name,b.sex,b.btherday,c.country,c.address,d.email
from a
inner join b on a.id=b.id
left join c on a.id=c.id
right join d on a.id=d.id
where 1=1
and a.name=?
为何要如此呢? 那是因为应用程序发给数据库的SQL 都是明文的字符编码,是我们人类看得懂的,机器看不懂的。机器只看得懂二进制的1010010。
因此数据库需要把传来的字符SQL命令翻译成二进制的1010,而这个工作叫做 编译或者是解释。搞过开发人都知道编译和解释都需要耗费CPU时间的。
虽然一个简单的SQL编译一次消耗不了多少CPU时间。如下图
其中4个SELECT 执千次以上,一天时间内24小时中。还好目前这些语句都绑定了变量。
虽然小凡仙我觉得,这五条大法或许很多人看不上眼,或许也解决不了你目前的SQL性能问题。如果你结合强拆,分库分表,三大配置,已经本章的5大法。那么小仙认为你的数据库性能问题,基本上进一步缩小在可控的范围中。