Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Sql语句的优化

3,672 views

Published on

sql语句优化的讨论

  • Be the first to comment

Sql语句的优化

  1. 1. Sql 语句的优化 <ul><li>1 关于 sql 的语句分类 </li></ul><ul><li>2sql 语句的执行顺序 </li></ul><ul><li>3 说说 where 语句 </li></ul><ul><li>4 关于子查询的巧用 </li></ul><ul><li>5update 、 delete 和 insert 语句的技巧 </li></ul><ul><li>6 关于关联的探讨 </li></ul><ul><li>7 一些细节的东西 </li></ul>
  2. 2. 一、关于 sql 的语句分类 1.DDL 语句 用于建立各种数据库对象。(库、表、主键、外键、约束、索引。。。等) 2.DML 语句 insert 、 delete 、 update 3DCL 语句 各种权限控制语句
  3. 3. <ul><li>二、 sql 语句的执行顺序 </li></ul><ul><li>执行顺序从右往左执行。 </li></ul><ul><li>1. 插入语句 Insert into table ( column1 , column12 ,。。。) values ( value1,value2,… )的执行也是如此。 </li></ul><ul><li>2.Select 语句 </li></ul><ul><li>select 字段列表 from table where 条件 group by 字段列表 having 条件 order by 字段 ( desc|asc ) </li></ul><ul><li>执行顺序: where  group by ->having->order by ->select 列投影。 </li></ul><ul><li>其中 where 的条件和 having 的条件是从右往左执行。 </li></ul><ul><li>3.Update table set 字段设置 where 条件 </li></ul><ul><li>执行顺寻: where ->set->update </li></ul><ul><li>Where 条件从右往左执行。 </li></ul><ul><li>4delete from table where 条件 </li></ul><ul><li>执行顺序: where- 》 delete </li></ul><ul><li>Where 条件从右往左执行。 </li></ul><ul><li>总结:执行中的性能消耗主要在 where 语句的查询。 </li></ul>
  4. 4. <ul><li>三、说说 where 语句 </li></ul><ul><li>3.1 执行顺序。(从右往左 ,尽量在右边条件过滤掉大部分行) </li></ul><ul><li>根据业务逻辑调整条件,可以提高效率。 如 </li></ul><ul><li>where sex =' 男 ' and age >20 慢 </li></ul><ul><li>where age >20 and sex =' 男 ' 快 (因为按性别分可以一次过滤掉一半的行) </li></ul><ul><li>3.2 like 尽量少用。 </li></ul><ul><li>like 语句进行模糊查询较慢。 </li></ul><ul><li>3.3 between and 不如 > < 快 </li></ul><ul><li>where between 20 and 40; 慢 </li></ul><ul><li>where age >20 and age <40; 快 </li></ul><ul><li>3.4 in 和 exists </li></ul><ul><li>delete from userinfo where userid in ( select userid from user_status ); 慢 </li></ul><ul><li>delete from userinfo A where exists ( select B.userid from user_status B where A.userid = B.userid ); 快 </li></ul><ul><li>( 由于是 delete 语句难以 inner join) </li></ul>
  5. 5. <ul><li>四、关于子查询的巧用 </li></ul><ul><li>4.1 in 语句和子查询性能的万恶之源 </li></ul><ul><li>通信证的一个 sql 优化的例子: </li></ul><ul><li>我在原有的项目中找到如下代码:(将性能瓶颈进行标红) </li></ul><ul><li>select U.USERID userid, </li></ul><ul><li>U.MOBILE mobile, </li></ul><ul><li>U.USERNAME username, </li></ul><ul><li>U.USERTYPE userType, </li></ul><ul><li>US.LOGIN_TIMES, </li></ul><ul><li>US.LASTLOGIN_DT, </li></ul><ul><li>US.FREE_DL free_dl, </li></ul><ul><li>UP.nickname nickname, </li></ul><ul><li> (case when us.modelid is null then 0 else us.modelid end) mobid , </li></ul><ul><li>(select ml.MODEL_NAME </li></ul><ul><li>from model_list ml </li></ul><ul><li>where ml.modelid = US.MODELID) mobModel </li></ul><ul><li>from USERINFO U, USER_STATUS US, USER_PROFILE UP </li></ul><ul><li> where U.USERID = US.USERID </li></ul><ul><li> and U.USERID = UP.USERID </li></ul><ul><li> AND (U.STATUS = 1 or U.STATUS = 2) </li></ul><ul><li> and (U.USERNAME =’zhanghe’) </li></ul>
  6. 6. <ul><li>原则一尽量使用系统函数 </li></ul><ul><li>(case when us.modelid is null then 0 else us.modelid end) mobid </li></ul><ul><li>可以用标准函数替代 </li></ul><ul><li>Nvl(us.modelid , 0 ) </li></ul><ul><li>原则二避免列映射里面用子查询。 </li></ul><ul><li>(select ml.MODEL_NAME </li></ul><ul><li>from model_list ml </li></ul><ul><li>where ml.modelid = US.MODELID) mobModel </li></ul><ul><li>这部分可以放到关联中 </li></ul><ul><li>原则三查询条件不要总是马后炮 </li></ul><ul><li>from USERINFO U, USER_STATUS US, USER_PROFILE UP </li></ul><ul><li>where U.USERID = US.USERID </li></ul><ul><li> and U.USERID = UP.USERID </li></ul><ul><li> AND (U.STATUS = 1 or U.STATUS = 2) </li></ul><ul><li> and (U.USERNAME =’zhanghe’) </li></ul><ul><li>这部分可以将特定表的查询提前。 </li></ul>
  7. 7. <ul><li>最后我的优化语句为: ( 红色部分位修改 ) </li></ul><ul><li>select U.USERID userid, </li></ul><ul><li>U.MOBILE mobile, </li></ul><ul><li>U.USERNAME username, </li></ul><ul><li>U.USERTYPE userType, </li></ul><ul><li>US.LOGIN_TIMES, </li></ul><ul><li>US.LASTLOGIN_DT, </li></ul><ul><li>US.FREE_DL free_dl, </li></ul><ul><li>UP.nickname nickname, </li></ul><ul><li> nvl(us.modelid,0) mobid , </li></ul><ul><li>ml.MODEL_NAME mobModel </li></ul><ul><li>from </li></ul><ul><li>( select * USERINFO U where (U.STATUS = 1 or U.STATUS = 2 )and (U.USERNAME =’zhanghe’) </li></ul><ul><li>inner join USER_STATUS US on U.USERID = US.USERID </li></ul><ul><li>inner join USER_PROFILE UP on U.USERID = UP.USERID </li></ul><ul><li>left join model_list ml on ml.modelid = US.MODELID </li></ul>
  8. 8. <ul><li>4.2 几乎所有的子查询都能变为表连接( 我已经把表优化到最烂。呵呵! ) </li></ul><ul><li>请看 </li></ul><ul><li>Select userid , username , </li></ul><ul><li>( select logintime from user_status where userid = u.userid ) logintime </li></ul><ul><li>from userinfo u where userid in ( select userid from user_status where userid = u.userid ) </li></ul><ul><li>where ( userid = 1024 or userid = 1025 ) and sex = ‘ 男’ and username like ‘’ 张 %; </li></ul><ul><li>此语句是有一位张先生号码可能是 1024 或 1025 。 </li></ul><ul><li>请大家谈谈如何将此语句优化。 </li></ul><ul><li>大家优化后结果: </li></ul>
  9. 9. <ul><li>五、 update 、 delete 和 insert 语句的技巧 </li></ul><ul><li>一次不只做一行,多行尽量做一次。 </li></ul><ul><li>5.1 Update 的技巧: </li></ul><ul><li>使用 case 语句分修改分类条件 </li></ul><ul><li>Update userinfo set 说明 = </li></ul><ul><li>( case </li></ul><ul><li>when age > 20 and age <30 then ‘ 年轻’ </li></ul><ul><li>when age > 30 and age <40 then ‘ 健壮’ </li></ul><ul><li>) , </li></ul><ul><li>… .. </li></ul><ul><li>Where sex = ‘ 男’ </li></ul><ul><li>以此类推一条语句可以更新好多的条件和字段。 </li></ul><ul><li>5.2 insert 语句(不说也知道) </li></ul><ul><li>Insert into table1 ( id , username ) select userid , ‘ 张三’ from userinfo </li></ul><ul><li>5.3 delete 和 truncate 间的选择。 </li></ul><ul><li>Delete 有事物可回滚, truncate 不可回滚。 </li></ul>
  10. 10. <ul><li>六、关于关联的探讨 </li></ul><ul><li>查询表顺序的影响 </li></ul><ul><li>在 FROM 后面的表中的列表顺序会对 SQL 执行性能影响,在没有索引及 ORACLE 没有对表进行统计分析的情况下 ORACLE 会按表出现的顺序进行链接,由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析, ORACLE 会自动先进小表的链接,再进行大表的链接) </li></ul><ul><li>From 表一 ,表二 ,表三 </li></ul><ul><li>From 表一 </li></ul><ul><li>Inner join 表二 </li></ul><ul><li>Inner join 表三 </li></ul><ul><li>以上的关联请将数据量最小的表放在后面, sql 是 从右往左 运行的。 </li></ul><ul><li>一些讨论: </li></ul><ul><li>客户 、订单、产品的关联。 </li></ul>
  11. 11. <ul><li>7. 一些细节的东西 </li></ul><ul><li>7.1Java 调用 sql 的提交尽量使用批量提交。 </li></ul><ul><li>7.2 存储过程会快很多。 </li></ul><ul><li>7.3 常用的复杂查询要写成 view 。 </li></ul><ul><li>7.4 尽量使用内部函数 </li></ul>
  12. 12. <ul><li>7.5 一些例句: </li></ul><ul><li>1. 减少对表的查询 </li></ul><ul><li>SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT </li></ul><ul><li>TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604) </li></ul><ul><li>2. 用 EXISTS 替代 IN 、用 NOT EXISTS 替代 NOT IN : </li></ul><ul><li>(高效) SELECT * FROM EMP ( 基础表 )WHERE EMPNO > 0 AND EXISTS (SELECT ‘X' FROM DEPT </li></ul><ul><li>WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB') </li></ul><ul><li>( 低效 )SELECT * FROM EMP ( 基础表 ) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB') </li></ul><ul><li>3. 用 EXISTS 替换 DISTINCT : </li></ul><ul><li>( 低效 ):SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E </li></ul><ul><li>WHERE D.DEPT_NO = E.DEPT_NO </li></ul><ul><li>( 高效 ):SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X' </li></ul><ul><li>FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO); </li></ul><ul><li>4. 用 >= 替代 > : </li></ul><ul><li>高效 :SELECT * FROM EMP WHERE DEPTNO >=4 </li></ul><ul><li>低效 :SELECT * FROM EMP WHERE DEPTNO >3 </li></ul><ul><li>5. 用 UNION 替换 OR ( 适用于索引列 ) : </li></ul><ul><li>高效 : SELECT LOC_ID , LOC_DESC , REGION FROM LOCATION WHERE LOC_ID = 10 </li></ul><ul><li>UNION </li></ul><ul><li>SELECT LOC_ID , LOC_DESC , REGION FROM LOCATION WHERE REGION = “MELBOURNE” </li></ul><ul><li>低效 :SELECT LOC_ID , LOC_DESC , REGION </li></ul><ul><li>FROM LOCATION </li></ul><ul><li>WHERE LOC_ID = 10 OR REGION = “MELBOURNE” </li></ul><ul><li>其他例子请看预习文档 </li></ul>
  13. 13. <ul><li>谢谢大家 </li></ul><ul><li>Sql 优化一言难尽 </li></ul>

×