丁俊:Sql与plsql开发实践

1,308 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,308
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

丁俊:Sql与plsql开发实践

  1. 1. DTCC2011 2011 ITPUB数据库技术大会基于ORACLE的SQL与PL/SQL开发实践 丁俊 2011年4月
  2. 2. 主要内容简介 ORACLE SQL Practices DTCC2011 全面的SQL知识体系 认识SQL的逻辑和物理执行顺序 从分析函数学习谈如何学SQL SQL编程的一点经验和案例 知识在于分享|2
  3. 3. 主要内容简介 ORACLE PL/SQL Practices DTCC2011 全面的PL/SQL知识体系 PL/SQL与SQL的关系 PL/SQL批量绑定、动态语句与绑定变量等 知识在于分享|3
  4. 4. 全面的ORACLE SQL知识体系 DTCC2011 ▪一般SQL ▪高级SQL . JOIN、SUBQUERY、GROUP BY、 .分析函数、层次查询、增强分 ORDER BY、FILTER操作、SET操作、 组、10g MODEL查询、11g递归 DDL、SCL,TCL、普通DML等 WITH、XML操作、高级 JUST DO IT DML:多表INSERT,基于 视图的DML操作,MERGE ▪常用函数 ▪版本新特性 . 数值、字符串、日期 . 10g正则表达式 . 统计函数 CBO . 11g LISTAGG、 . 类型转换函数 PIVOT、UNPIVOT等• 一般 . 其他函数:如分析函数、对 象函数、管道函数、层次查询 中的一些函数 知识在于分享|4
  5. 5. 认识SQL的逻辑和物理执行顺序 DTCC2011认识SQL的逻辑执行顺序 何为SQL的逻辑执行顺序 认识SQL逻辑执行顺序的好处 简单案例分析 知识在于分享|5
  6. 6. 认识SQL的逻辑和物理执行顺序 逻辑顺序 DTCC2011 逻辑执行顺序主要指SELECT、INSERT、DELETE、 UPDATE等操作的语法层次的执行顺序。尤其要清楚SELECT语 法层次的顺序。 ORDERFROM Subquery、join、nested SQL etc. SELECT Hierarical WHERE Analytical GROUP 知识在于分享|6
  7. 7. 认识SQL的逻辑和物理执行顺序 逻辑顺序续 DTCC2011理解SQL的逻辑执行顺序,可以大幅度减少错误SQL的编写。理解SQL的逻辑执行顺序,可以深化对SQL的认识,有利于处理更加复杂的业务逻辑。 知识在于分享|7
  8. 8. 认识SQL的逻辑和物理执行顺序 逻辑顺序续 DTCC2011▪ --先递归后过滤,6 rows returned▪ SELECT employee_id,manager_id,LEVEL lv▪ FROM hr.employees▪ WHERE manager_id=148▪ START WITH manager_id IS NULL▪ CONNECT BY PRIOR employee_id = manager_id▪ ;▪▪ --先过滤后递归,0 rows returned▪ SELECT employee_id,manager_id,LEVEL lv▪ FROM▪ (SELECT employee_id,manager_id▪ FROM hr.employees▪ WHERE manager_id=148▪ )▪ START WITH manager_id IS NULL▪ CONNECT BY PRIOR employee_id = manager_id▪ ; 知识在于分享|8
  9. 9. 认识SQL的逻辑和物理执行顺序 物理执行顺序 DTCC2011认识SQL的物理执行顺序 SQL的物理执行顺序就是实际的EXECUTION PATH 物理执行顺序依赖于CBO优化器组件,非常复杂 案例分析 知识在于分享|9
  10. 10. 认识SQL的逻辑和物理执行顺序 CBO简介 DTCC2011 Table statistics Dynamic sampling index statisticscolumn statistics DBMS_STATScolumn histogram System statistics 知识在于分享|10
  11. 11. 认识SQL的逻辑和物理执行顺序 物理执行顺序案例 DTCC2011 2 - filter(TO_NUMBER("BID_PRICE")>0) 知识在于分享|11
  12. 12. 续 案例总结 DTCC2011典型的Predicate Push导致的问题当然,大部分时候它很有效总结:正确的表设计良好的SQL编写习惯好东西不是总是有效查看计划是解决此类问题行之有效的方法 知识在于分享|12
  13. 13. 从分析函数学习谈如何学SQL DTCC2011甲:我有个SQL,你能帮我用分析函数改写下吗?SELECT owner,object_type FROM demo2 WHERE owner=DINGJUN123 AND object_type=(SELECT MAX(object_type) FROM demo2 WHERE owner=DINGJUN123);乙:相关列有索引吗?甲:owner有索引,选择性还可以,我就是想用分析函数改 写看看?乙:哦,知道了,这是典型的top-n查询。 知识在于分享|13
  14. 14. 从分析函数学习谈如何学SQL 续 DTCC2011SELECT owner,object_typeFROM ( 分析函数真不错,那 么学吧SELECT owner,object_type, dense_rank() over(ORDER BY object_type DESC) rn FROM demo2 WHERE owner=DINGJUN123) WHERE rn=1;对比:原始SQL多次扫描索引和回表,返回180行,逻辑读730,COST:1205.不 算差。 用分析函数改写后:只需要通过一次索引访问表,逻辑读353,COST:721.缺 点:需要排序。可以再优化吗?OK,可以根据表的访问特点,如果建立(owner,object_type DESC) 组合索引,会更好,DESC消除分析函数的排序,使用后原始语句:逻辑读102, COST:154.分析函数COST:178,逻辑读16,并且消除了排序。 demo见备注。 知识在于分享|14
  15. 15. 从分析函数学习谈如何学SQL 特点 DTCC2011从文档提取分析函数特点:1. 分析函数依赖于分析子句对当前行所属的分组进行分析函 数计算。用于复杂的行间和累计值的计算。2. 分析函数与组函数不同。根据1的特点,分析函数同时能计 算分组值,并且还能保留当前行的其他列值。--重要特性2. 分析函数分类:排名 (rank,dense_rank,row_number,first/last,ntile等)、聚 合报表函数(sum,count等以及ratio_to_report)、行比 较(lead/lag,first_value/last_value)、数学统计 (stddev,var_pop等)等函数。 知识在于分享|15
  16. 16. 从分析函数学习谈如何学SQL 语法结构 DTCC2011分析函数的语法结构特点: 知识在于分享|16
  17. 17. 从分析函数学习谈如何学SQL 语法结构续 DTCC2011 知识在于分享|17
  18. 18. 从分析函数学习谈如何学SQL 语法结构关注点 DTCC2011 ROWS关注文档中的 Vs注意点和限制 RANGE PARTITION BY ORDER BY Analytic SQL UNBOUNDED PRECEDING Analytic FOLLOWING Function CURRENT ROW 知识在于分享|18
  19. 19. 从分析函数学习谈如何学SQL ROWS与RANGE DTCC2011WITH t AS(SELECT (CASE WHEN LEVEL IN (1,2) THEN 1 WHEN LEVEL IN (4,5) THEN 6 ELSE LEVEL END) IDFROM dual CONNECT BY LEVEL<10)--默认排序SELECT id,SUM(ID) over(ORDER BY ID) default_sum,--逻辑行上限到当前行,此当前行是逻辑当前行 SUM(ID) over(ORDER BY ID RANGE BETWEEN unbounded preceding AND CURRENT ROW) range_unbound_sum,--物理当前行,按排序后的行位置计算 SUM(ID) over(ORDER BY ID ROWS BETWEEN unbounded preceding AND CURRENT ROW) rows_unbound_sum,--下面两条与上面的比较,换成了对窗口有一定的限制,同样分为逻辑行和物理行 SUM(ID) over(ORDER BY ID RANGE BETWEEN 1 preceding AND 2 following) range_sum, SUM(ID) over(ORDER BY ID ROWS BETWEEN 1 preceding AND 2 following) rows_sumFROM t; 知识在于分享|19
  20. 20. 从分析函数学习谈如何学SQL ROWS与RANGE续 DTCC2011 知识在于分享|20
  21. 21. 从分析函数学习谈如何学SQL 经典排名函数 DTCC2011▪ WITH t AS▪ (SELECT CASE WHEN LEVEL IN (1,2) THEN 1▪ WHEN LEVEL IN (3,4) THEN 2▪ ELSE LEVEL▪ END ID▪ FROM dual▪ CONNECT BY LEVEL <6)▪ SELECT row_number() over(ORDER BY ID) rn,▪ rank() over(ORDER BY ID) rk,▪ dense_rank() over(ORDER BY ID) dr▪ FROM t; 知识在于分享|21
  22. 22. 从分析函数学习谈如何学SQL 经典排名函数续 DTCC2011▪ SELECT employee_id,salary,department_id,rn▪ FROM (▪ SELECT employee_id,salary,department_id,▪ row_number() over(PARTITION BY department_id ORDER BY salary DESC) rn▪ FROM hr.employees emp▪ ) WHERE rn < 4; 知识在于分享|22
  23. 23. 从分析函数学习谈如何学SQL 连续数问题 DTCC2011▪ dingjun123@ORADB> select id,num,val from test_tab;▪ ID NUM VAL▪ ---------- ---------- ----------▪ 1 1 50▪ 1 2 100▪ 1 3 150▪ 1 5 250▪ 2 1 100▪ 2 3 400▪ 3 1 100▪ 3 2 200▪ 要求:ID相同,NUM连续增长的,对val求和,并显示最小的num 知识在于分享|23
  24. 24. 从分析函数学习谈如何学SQL 连续数问题续 DTCC2011解决方法:对连续的数构造一个相同的标识。这样 就能确定连续了。 知识在于分享|24
  25. 25. 从分析函数学习谈如何学SQL keep与first、last DTCC2011 知识在于分享|25
  26. 26. 从分析函数学习谈如何学SQL keep与first、last续 DTCC2011Keep与first、last经常不用于分析函数,而直接用 于组函数,对一列排序,求另一列的聚合函数值。语法中用的是dense_rank,所以对于first,last可 能会有多行值,因此外面用聚合函数取聚合值。 知识在于分享|26
  27. 27. 从分析函数学习谈如何学SQL keep与first、last续 DTCC2011 ▪ WITH t AS ▪ (SELECT 1 ID,1 num,1 val FROM dual UNION ALL ▪ SELECT 1 ID,2 num,2 val FROM dual UNION ALL ▪ SELECT 2 ID,3 num,1 val FROM dual UNION ALL ▪ SELECT 3 ID,4 num,1 val FROM dual) ▪ SELECT ID,MAX(num) KEEP (dense_rank LAST ORDER BY val ASC) max_last_asc, ▪ MIN(num) KEEP (dense_rank FIRST ORDER BY val ASC) min_first_asc, ▪ MAX(num) KEEP (dense_rank LAST ORDER BY val DESC) max_last_desc, ▪ MIN(num) KEEP (dense_rank FIRST ORDER BY val DESC) min_first_desc ▪ FROM t ▪ GROUP BY ID; 知识在于分享|27
  28. 28. 从分析函数学习谈如何学SQL keep与first、last续 DTCC2011▪ --用于分析函数,over里只允许partition▪ WITH t AS▪ (SELECT 1 ID,1 num,1 val FROM dual UNION ALL▪ SELECT 1 ID,2 num,2 val FROM dual UNION ALL▪ SELECT 2 ID,3 num,1 val FROM dual UNION ALL▪ SELECT 3 ID,4 num,1 val FROM dual)▪ SELECT ID,num,val,MAX(num) KEEP (dense_rank LAST ORDER BY val ASC) over() max_last_asc,▪ MIN(num) KEEP (dense_rank FIRST ORDER BY val ASC) over() min_first_asc,▪ MAX(num) KEEP (dense_rank LAST ORDER BY val DESC) over() max_last_desc,▪ MIN(num) KEEP (dense_rank FIRST ORDER BY val DESC) over() min_first_desc▪ FROM t; 知识在于分享|28
  29. 29. 从分析函数学习谈如何学SQL keep与first、last续 DTCC2011▪ SELECT yy,mm,NAME,SUM(qty) s_qty,AVG(price) avg_price,▪ MAX(invent) KEEP (dense_rank LAST ORDER BY dd) last_invent FROM sale▪ GROUP BY yy,mm,NAME;▪ YY MM N S_QTY AVG_PRICE LAST_INVENT▪ ---------- ---------- - ---------- ---------- ---------- -▪ 2011 1A 30 20 7▪ 2011 2A 40 25 10▪ 已选择2行。 知识在于分享|29
  30. 30. 从分析函数学习谈如何学SQL 报表统计ratio_to_report DTCC2011▪ 求部门salary总和占公司所有salary和的比率,并且显示部门salary,所有 salary▪ SELECT department_id ,sum(salary) dept_sum,▪ SUM(SUM(salary)) over() all_sum,▪ round(SUM(salary)/(SUM(SUM(salary)) over()),2)*100||% ration▪ FROM hr.employees▪ GROUP BY department_id▪ ORDER BY 1;▪ --专业报表百分比函数,计算参数值占所有值的百分比▪ SELECT department_id ,sum(salary) dept_sum,▪ SUM(SUM(salary)) over() all_sum,▪ round(ratio_to_report(SUM(salary)) over(),2)*100||% ration▪ FROM hr.employees▪ GROUP BY department_id▪ ORDER BY 1; 知识在于分享|30
  31. 31. 从分析函数学习谈如何学SQL 填充gap行 DTCC2011 知识在于分享|31
  32. 32. 从分析函数学习谈如何学SQL 模拟SQL*PLUS BREAK DTCC2011 SELECT decode(lag(department_id,1) over(PARTITION BY department_id ORDER BY first_name), department_id,NULL,department_id ) newdepartment_id, first_name FROM hr.employees WHERE department_id<40 ORDER BY department_id,first_name; 知识在于分享|32
  33. 33. 从分析函数学习谈如何学SQL 金额摊派 DTCC2011 跟newkid大师学SQLdingjun123@ORADB> select * from demo7_1; ID AMOUNT---------- ---------- 先均分,采用trunc精确到分 1 100 然后用分析函数求均分后的金额 总和,并按均分金额降序设定行 2 50 号,最后(原始金额-均分总金额) *100,如果行号<=此值,则+0.01,已选择2行。 否则不变。dingjun123@ORADB> select * from demo7_2; ID PERSONS---------- ---------- 1 3 2 2已选择2行。 知识在于分享|33
  34. 34. 从分析函数学习谈如何学SQL 金额摊派续 DTCC2011SELECT ID, persons,(CASE WHEN rn <= (amount - amount2) * 100 THEN 0.01 ELSE 0 END) + je AS je,amount --然后排序,与总金额有差额的补0.01FROM (SELECT t.*, SUM(je) OVER(PARTITION BY id) AS amount2, ROW_NUMBER() OVER(PARTITION BY id ORDER BY je DESC) rn FROM ( --先展开记录数,用trunc先平均,只舍不入 SELECT tt.* FROM (SELECT t2.id, t2.persons, TRUNC(t1.amount /t2.persons, 2) je, t1.amount amount FROM demo7_1 t1, demo7_2 t2 WHERE t1.id = t2.id ) tt, --构造最大的人数序列 (SELECT LEVEL rn FROM dual CONNECT BY LEVEL <= (SELECT MAX(persons) max_num FROM demo7_2) ) tm WHERE tt.persons >= tm.rn) t 知识在于分享|34
  35. 35. 从分析函数学习谈如何学SQL 总结 DTCC2011 分析函数可以实现复杂的行间计算功能,诸如累计值,行间比较,报表统计等功能。学习分析函数要把握每种分析函数的特点,并掌握分析函数中的关键元素的联系区别:比如ROWS与RANGE区别,window子句与partition、order by的关系,掌握窗口、当前行的概念。此外ORACLE还支持自定义的聚集函数,可以实现分析函数的功能,可以参考Data Cartridge Developers Guide。 知识在于分享|35
  36. 36. SQL编程的一点经验和案例1 标量子查询与join DTCC20111.清楚对象间的关系以及相关约束,索引等,编写正 确的SQL。 知识在于分享|36
  37. 37. SQL编程的一点经验和案例 2 DTCC20112.查看计划是解决SQL问题的主要途径。查看计划可 以了解更多SQL写法并能够进行一般的trouble shooting。 知识在于分享|37
  38. 38. SQL编程的一点经验和案例 3 DTCC20113.不要滥用绑定变量,必须了解表的统计信息,特 别是是否有直方图。 cursor_sharing histograms 11g ACS 知识在于分享|38
  39. 39. SQL编程的一点经验和案例 4 DTCC20114.不要迷信规则,以自己的实际测试为准。 知识在于分享|39
  40. 40. SQL编程的一点经验和案例 4续 DTCC2011 知识在于分享|40
  41. 41. SQL编程的一点经验和案例 5 DTCC20115.update很慢,如何能提速?(一般情况) update t1 set col=(select t2.col from t2 where t1.colx=t2.coly…..) where exists(select 1 from t2 where ….);  对象间的关系很重要 a. merge into t1 using t2 on (condition) when matched set t1.col =t2.col; b. --update inline view bypass_ujvc hint update (select t1.col t1_col,t2.col t2_col where condition) set t1_col = t2_col; c. ctas and constraints,index…rename and drop d.见pl/sql 批处理 知识在于分享|41
  42. 42. SQL编程的一点经验和案例 6 DTCC20116.良好的设计和编程习惯。 where to_char(date,’fmt’)、where trunc(date,’fmt’),where to_number(char)… 表明明存放的是date类型,竟然设计成 varchar2… 你还准备用varchar2吗? 知识在于分享|42
  43. 43. 全面的ORACLE PL/SQL知识体系 DTCC2011 PL/SQL高级 PL/SQL基础 Bulk process Procedure Pipelined function Function I/O Triggers External pl/sql Package Pl/sql 语法和组件 Oop Security … Such as type、control Built in package 、types、cursor、 … exception handler… 知识在于分享|43
  44. 44. PL/SQL与SQL的关系 DTCC2011 PL/SQL engine procedural Procedural PL/SQL statement block executor SQL SQL statement减少交互次数一定程 度可优化 executor PL/SQL Oracle database server 知识在于分享|44
  45. 45. PL/SQL与SQL的关系 续 DTCC20111.PL/SQL有更多的内置type:boolean,record,ref cursor,pls_integer等,而且有的最大长度限制与 SQL不同。2.SQL的有些内置函数不能直接在PL/SQL中使用,比如 decode,group function。3.PL/SQL还有自己的操作符,比如**,2**3=8,但是SQL 中不能使用。4.PL/SQL中可以使用几乎所有的SQL语句,但是SQL里 只能使用特定的PL/SQL功能。 知识在于分享|45
  46. 46. PL/SQL与SQL的关系 续 DTCC2011 知识在于分享|46
  47. 47. PL/SQL编程的一点经验和案例-批处理 DTCC2011 PL/SQL run-time engine SQL engine PL/SQL blockFORALL i IN 1..10000 Procedural SQL statement INSERT … (collections1(i), statement executor collections2(i), …); executor 知识在于分享|47
  48. 48. PL/SQL编程的一点经验和案例-批处理续 DTCC2011批量绑定的内容:• SELECT 、 FETCH BULK COLLECT INTO• RETURNING• FORALL : INSERT, UPDATE, DELETE 知识在于分享|48
  49. 49. PL/SQL编程的一点经验和案例-批处理续 DTCC2011静态SQL批量绑定:▪ SELECT .... BULK COLLECT INTO ..▪ FETCH CURSOR_name BULK COLLECT INTO ... [LIMIT]▪ RETURNING .... BULK COLLECT INTO ...动态SQL批量绑定:▪ 1.OPEN FOR sql_stmt▪ FETCH ... BULK COLLECT INTO ... [LIMIT]▪ 2. EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO ....▪ 3.动态sql里先要returing INTO 绑定变量,外面return BULK COLLECT INTO 知识在于分享|49
  50. 50. PL/SQL编程的一点经验和案例-批处理续 DTCC2011▪ DECLARE▪ l_start NUMBER;▪ BEGIN▪ l_start := dbms_utility.get_time;▪ FOR rec IN (SELECT * FROM All_Objects) LOOP▪ INSERT INTO demo13 VALUES rec;▪ END LOOP;▪ DBMS_OUTPUT.put_line(elapsed time is ▪ || (dbms_utility.get_time - l_start));▪ END;----73839条插入,消耗时间14.087s 知识在于分享|50
  51. 51. PL/SQL编程的一点经验和案例-批处理续 DTCC2011▪ DECLARE▪ l_start NUMBER;▪ i NUMBER :=0;▪ BEGIN▪ l_start := dbms_utility.get_time;▪ FOR rec IN (SELECT * FROM All_Objects) LOOP▪ i := i+1;▪ INSERT INTO demo13 VALUES rec;▪ IF MOD(i,1000) = 0 THEN▪ COMMIT;▪ END IF;▪ END LOOP;▪ COMMIT;▪ DBMS_OUTPUT.put_line(elapsed time is ▪ || (dbms_utility.get_time - l_start));▪ END;▪ ----73839条插入,消耗时间15.429s 知识在于分享|51
  52. 52. PL/SQL编程的一点经验和案例-批处理续 DTCC2011▪ DECLARE▪ l_start NUMBER;▪ CURSOR all_objects_cur IS SELECT * FROM all_objects;▪ TYPE all_objects_nt IS TABLE OF all_objects_cur%ROWTYPE;▪ l_all_objects all_objects_nt;▪ BEGIN▪ l_start := dbms_utility.get_time;▪ OPEN all_objects_cur;▪ FETCH all_objects_cur▪ BULK COLLECT INTO l_all_objects;▪ FORALL idx IN 1 .. l_all_objects.COUNT▪ INSERT INTO demo13 VALUES l_all_objects(idx);▪ DBMS_OUTPUT.put_line(elapsed time is ▪ || (dbms_utility.get_time - l_start));▪ END;----73839条插入,消耗时间9.36s,还是不够好,消耗PGA资源大 知识在于分享|52
  53. 53. PL/SQL编程的一点经验和案例-批处理续 正宗的批处理 DTCC2011 如果有bulk collect改为▪ DECLARE for效率一样▪ l_start NUMBER;▪ CURSOR all_objects_cur IS SELECT * FROM all_objects;▪ TYPE all_objects_nt IS TABLE OF all_objects_cur%ROWTYPE;▪ l_all_objects all_objects_nt;▪ BEGIN▪ l_start := dbms_utility.get_time;▪ OPEN all_objects_cur;▪ FETCH all_objects_cur▪ BULK COLLECT INTO l_all_objects LIMIT 100;▪ FORALL idx IN 1 .. l_all_objects.COUNT▪ INSERT INTO demo13 VALUES l_all_objects(idx);▪ DBMS_OUTPUT.put_line(elapsed time is ▪ || (dbms_utility.get_time - l_start));▪ END;----73839条插入,消耗时间0.016s 知识在于分享|53
  54. 54. PL/SQL编程的一点经验和案例-批处理续 DTCC2011 批量数组绑定,需要利用bulk collect获取批量数据,然后限制limit,limit一般100,可以稍微大点,超过1000一般不好,具体可以通过测试后取1个比较适合的值。for也是可以批量绑定的。 知识在于分享|54
  55. 55. PL/SQL编程的一点经验和案例 update和delete DTCC2011--0.764s 73841 row,normal update:7.16s▪ BULK COLLECT INTO l_all_objects_ids,l_all_objects_names LIMIT 100;▪ FORALL idx IN 1 .. l_all_objects_names.COUNT▪ UPDATE demo15 SET object_name =l_all_objects_names(idx)▪ WHERE object_id=l_all_objects_ids(idx); 知识在于分享|55
  56. 56. PL/SQL编程的一点经验和案例-动态语句与绑定变量 DTCC2011▪ CREATE OR REPLACE PROCEDURE sp_t▪ (i_tabname VARCHAR2, i_date DATE,▪ o_count OUT NUMBER)▪ AS▪ v_sql VARCHAR2(1000);▪ BEGIN▪ v_sql := SELECT COUNT(*) FROM || i_tabname || WHERE done_date> ||▪ i_date;▪ DBMS_OUTPUT.PUT_LINE(v_sql); 绑定变量是解决此 类问题的利器。▪ EXECUTE IMMEDIATE v_sql 绑定变量虽好,▪ INTO o_count; 可不要乱用哦▪ END;▪ / 知识在于分享|56
  57. 57. DTCC2011Welcome to ITPUB ORACLE开发版! 知识在于分享|57
  58. 58. DTCC2011Any question? 知识在于分享|58
  59. 59. DTCC2011 知识在于分享|59

×