数据库优化与问题
序言,本人做了将近的一年报表的开发,大多时间写sql,我想把自己学到关于数据库知识分享给大家,这里主要说一下常用的数据库优化
什么是数据库优化
我的认识是,就是操作数据花的时间最少,准确性更高。这里讲一下常用sql优化技巧与生活常见的问题一般遇到去重复的数据,一般会用到distinct函数,可以用group by 代替,注意一点时distinct不能和count(1)连用
例子
SELECT DISTINCT(mgr) FROM emp
–用group by 代替distinct函数
SELECT mgr FROM emp GROUP BY mgr
–正确的写法
SELECT COUNT(1),mgr FROM emp GROUP BY mgr
–错误的写法
SELECT COUNT(1),DISTINCT(mgr)FROM emp在用group by 时,不一把所有的要查询的列都要放在group by 后面,有时候可以在max(列名)
例子
–两个查询结果一样,第一个效率更好
SELECT ename,max(job),max(mgr) FROM emp GROUP BY enameSELECT ename,job,mgr FROM emp GROUP BY ename,job,mgr
在比较大小时注意
例子
SELECT * FROM EMP WHERE MGR>3
优化后
select * from emp where mgr>=4在做查询,尽量不要进行全表查询
例子
–全表查询
SELECT * FROM EMP
–针对某一列
SELECT mgr FROM EMPcount(1)与count(*)区别
count(1)是针对第一列进行统计,不统计第一列为空的现象
但count(*)是统计为空现象sum()与count()的区别
sum是某一列的和,count是计数的
sum(0)就是0求百分比出现的问题
例子
会出现小数点前不显示0,最好的解决办法
SELECT to_char(round(800/1000,2)*100,’999’)||’%’ FROM dual一般count(1)结果没有数据时会显示0,一般后面有条件的话,就不会显示零
尽量减少大表之间关联,特别是外连接,改用嵌套SELECT
例如
SELECT a.deptno,b.deptno FROM emp a,dept b WHERE a.deptno=b.deptno
–性能优
SELECT (SELECT b.deptno FROM dept b WHERE a.a.deptno=b.deptno) a,a.deptno FROM emp a有索引,但全表扫表时,需要注意传入的参数,不一定是索引不好用
对字段使用函数后进行比较,无法利用索引。in 可以改成exists函数
例子
SELECT * FROM emp a,dept b
WHERE a.deptno=b.deptno
–优化
SELECT * FROM emp a WHERE Exists(SELECT 1 FROM dept WHERE a.deptno=b.deptno)SELECT * FROM emp a WHERE a.deptno in(select b.deptno from dept d where a.deptno=b.deptno)
–优化
SELECT * FROM emp a WHERE exists(select b.deptno from dept d where a.deptno=b.deptno)count()与sum()
例子
select count(*)from emp where mgr>100
select count(*) from emp where mgr>200
优化
select count(case when mgr>100 then 1 else null end),
count(case when mgr>200 then 1 else null end),from empsql语句的执行顺序是自下而上,从右到左,所以写select语句时,要把限制最大的条件写在最下面
sql语句用大写的;因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行
避免在索引列上使用NOT 通常,
我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.union all 代替 union,因为union all有自动排序功能
用in 代替or
避免在索引列上使用IS NULL和IS NOT NULL
多个时间范围,查询结果为去除重复时间范围的时间
例子
SELECT MIN(cykssj), MAX(cyjssj)
FROM (SELECT cykssj,
cyjssj,
SUM(broken) OVER(ORDER BY cykssj, cyjssj) flag
FROM (SELECT t.*,
(CASE
WHEN cykssj <= MAX(cyjssj)
OVER(ORDER BY cykssj,
cyjssj ROWS BETWEEN UNBOUNDED
PRECEDING AND 1 PRECEDING) THEN
0
ELSE
1
END) AS broken
FROM fw_zjjh t))
GROUP BY flag;分级函数
例子
select ZZMC,LEVEL from xt_zz
WHERE ROWNUM<2
start WITH zzdm=’01’ –从哪个级别代码查询
connect by prior zzdm = sjdm–分级的条件判断某一个字符串是否包含某个字符串或者字符
例子
–查询xxmc中包括工单两个字的xxmc
select c.xxmc rom kfgdxx c where instr(c.xxmc,’工单’)>0with as 用法
select * from
(SELECT LEVEL AS lv FROM DUAL CONNECT BY LEVEL < 20
) tt
WHERE tt.lv > 10 AND tt.lv < 15
–优化后
with TT as(SELECT LEVEL AS lv FROM DUAL CONNECT BY LEVEL < 20 )
select lv from TT
WHERE lv > 10 AND lv < 15按照列合计
例子
select nvl(to_char(t.cjsj,’MM’),’合计’),sum(t.hwl) ,sum(t.zhwl) from FW_TYSL_95598 t GROUP BY ROLLUP(to_char(t.cjsj,’MM’))列转行用sum 与group by 和listagg group by都可以
如果你遇到列和行都是动态改变的,可以有两种方式实现,可以把列先查出来,存入一个临时表,再把行查出来存入另一个临时表。最后进行双层循环,就可以实现。另一种方法,就是在前台实现行的动态改变,在数据中实现列的改变
例子
1 A B
2 B C
3 B A
应该显示
1 A B
2 B C
–实现的原理
select count(1)from(
select 2||1 from dual
union
select 1||2 from dual
minus
select 1||2 from dual)