自己遇到的一些SQL优化
字符的分隔
(思想,先构造在拼接)
SELECTa.id,b.NAME,A.WORK_TYPE,b."ID"
FROMCRD.T_CRD_SCORE_CONFIGa
leftJOINEMERP.T_BASE_WORK_TYPE_ALLbon','||A.WORK_TYPE||','like'%,'||b.id||',%'GROUPBYA.ID
分组函数:GROUP BY
分组函数,可以多次分组
提高GROUP BY 语句的效率,可以通过将不需要的记录在GROUP BY 之前过滤掉
子查询
这次写代码的时候,有一些字段上线前着急要和实际的业务逻辑,使用了子查询,有的可以使用连接查询,但是没有优化
记录的标记字段
这次编写代码的时候,标记这条记录是否删除,使用,显示,在编写SQL的时候出现了一些漏写的字段,以后再写的时候,一定要注意全
表空间(用户)
在编写SQL的时候,没有注意在表前标记空间名(用户)。
OR的使用
OR一定要合理运用,总忘记这个
ORDER BY 的使用
1. 只有ORDER BY 子句中可以使用select列表中列的别名
2. 使用了ORDER BY子句的查询不能用作表表达式(视图、内联表值函数、子查询、派生表和共用表达式)
3. 在分页的时候,如果是多表连接的,要是条件排序的条件的值一致,在分页的时候可能两次的结果有重复数据。
exts和in用法
1. exists对外表做循环,每次循环对内表查询;in将内表和外表做hash连接
2. 使用exists oracle会先检查主查询,使用in,首先执行子查询,将结果存储在临时表中
3. 如果两个表大小相当,in和exists差别不大
4. 如果两个表大小相差较大则子查询表大的用exists,子查询表小的用in
5.尽量不要使用not in
union和union all
1. 使用场景:需要将两个select语句结果整体显示时,可以使用union和unionall
2.union对两个结果集取并集不包含重复结果同时进行默认规则的排序;而union all对两个结果集去并集,包括 重复行,不进行排序
3.union需要进行重复值扫描,效率低,如果没有要删除重复行,应该使用union all
4.insersect和minus分别交集和差集,都不包括重复行,并且进行默认规则的排序
5.可以将多个结果集合并
6.必须保证select集合的结果有相同个数的列,并且每个列的类型是一样的(列名不一定要相同,会默认将第一个结果的列名作为结果集的列名)
指定where的条件顺序
1. 默认情况下,Oracle采用自下而上的顺序解析where字句,因此在处理多表查询的时候,表之间的连接必须写在其他的where条件之前,但是过滤数据记录的条件则必须写在where子句的尾部,以便在过滤了数据之后再进行连接处理,这样可以提升sql语句的性能
LEFT--JOIN 注释事项
在使用left-join的时候一定要注意顺序问题。
SQL语句尽量用大写的
因为oracle总是先解析SQL语句,把小写的字母转换成大写的再执行。
使用表的别名
当在SQL语句中连接多个表时, 尽量使用表的别名并把别名前缀于每个列上。这样一来,就可以减少解析的时间并 减少那些由列歧义引起的语法错误。
选择最有效率的表名顺序(只在基于规则的优化器(RBO)中有效)
ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表也称为驱动表,driving table)将被最先处理,在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表。
避免使用耗费资源的操作
带有DISTINCT、UNION、MINUS、INTERSECT、ORDER BY的SQL语句会启动SQL引擎执行
耗费资源的排序(SORT)功能。DISTINCT需要一次排序操作,而其他的至少需要执行两次排序。
通常,带有UNION、MINUS、INTERSECT的SQL语句都可以用其他方式重写。
如果数据库的SORT_AREA_SIZE调配得好,使用UNION,MINUS,INTERSECT也是可以考虑。
用Where子句替换HAVING子句
避免使用HAVING子句,HAVING只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序,总计等操作。最好能通过WHERE子句限制记录的数目。(非oracle中)on、where、having这三个都可以加条件的子句中,on是最先执行,where次之,having最后。
避免在索引列上使用计算
WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。
BETWEEN AND
取值是两边都要。
NVL2(expr1,expr2,expr3)
NVL2(表达式,不为空设值,为空设值)
to_char用法
(1)用作日期转换
to_char(date,'格式');
select to_char(sysdate,'yyyy-MM-dd HH24:mi:ss') from dual;
(2)处理数字
to_char(number,'格式');
select to_char(88877) from dual;
select to_char(1234567890,'099999999999999') from dual;
select to_char(12345678,'999,999,999,999') from dual;
select to_char(123456,'99.999') from dual;
select to_char(1234567890,'999,999,999,999.9999') from dual;
(3) 处理钱
to_char(salary,'$99,99');
select TO_CHAR(123,'$99,999.9') from dual;
(4)用于进制转换:将10进制转换为16进制;
select to_char(4567,'xxxx') from dual;
select to_char(123,'xxx') from dual;
to_date
select sysdate,to_date('20170615','yyyymmdd')from dual;
select sysdate,to_date('20170615','yyyy-mm-dd')from dual;
select sysdate,to_date('20170615','yyyy/mm/dd')from dual;
select sysdate,to_date('20170615','yyyy-mm-dd hh24:mi:ss')from dual;
应尽量避免在 where 子句中使用 or 来连接条件
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10
union all
select id from t where Name = 'admin'
模糊查询
当模糊匹配以%开头时,该列索引将失效,若不以%开头,该列索引有效。
常用函数
FLOOR(x) 返回小于x的最大整数值
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和
LEFT(str,x)返回字符串str中最左边的x个字符
TRIM(str)去除字符串首部和尾部的所有空格
UCASE(str)或UPPER(str) 返回将字符串str中所有字符转变为大写后的结果
优化总结口诀
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有or, 索引失效要少用;
VAR引号不可丢,SQL高级也不难;
如何分析SQL
1.观察,至少跑一天,看看生产的慢SQL情况。
2.开启慢查询日志,设置阀值,比如超过5秒钟就是慢SQL,并将它抓取出来
3.explain+慢SQL分析
4.show profile
5.DBA进行SQL数据库服务器的参数调优
总结:
1.慢查询的开启并捕获
2.explain+慢SQL分析
3.show profile查询SQL在MySql里面的执行细节和生命周期情况
4.SQl数据服务器的参数调优