You are on page 1of 27

高效SQL语句编写

杨廷琨

YUNHE ENMO (BEIJING) TECHNOLOGY CO.,LTD 云和恩墨 成就所托

云和恩墨成就所托
云和恩墨 成就所托
个人介绍

 杨廷琨(yangtingkun)
 Oracle ACE Director
 ITPUB数据库管理区版主
 ACOUG核心会员副总裁
 参与编写《Oracle数据库性能优化》、
《Oracle DBA手记》、《Oracle DBA手记3》
和 《 Oracle性能优化与诊断案例精选》
 十九年的一线DBA经验
 个人BLOG中积累了2500篇原创技术文章
 云和恩墨CTO

云和恩墨成就所托
云和恩墨 成就所托
内容

⚫ 培训包含:
• SQL

⚫ 培训不含:
• 范式设计
• 物理建模
• SQL语法
• 索引结构
• 数据库优化

⚫ 运行环境
• CREATE TABLE T AS SELECT ROWNUM ID, A.* FROM
DBA_OBJECTS A;
云和恩墨成就所托
云和恩墨 成就所托
高效SQL的必要性

⚫ SQL是世界上第二大的编程语言,超过50%的开发
者使用SQL

⚫ 80%的数据库问题是SQL引起的

⚫ 80%的性能问题来自20%的SQL语句

⚫ 高并发环境中,单条SQL语句可能导致整个数据库
出现性能故障

云和恩墨成就所托
云和恩墨 成就所托
YUNHE ENMO (BEIJING) TECHNOLOGY CO.,LTD

1 合理运用新特性

2 数据集整体处理

3 设计SQL执行计划

4 严格过滤数据

云和恩墨 成就所托
合理运用新特性

目标:从一张表取数据插入到另一张表中,此外需要
为插入的目标表做一个应用级的日志表,也就是说在
插入目标表的同时,还需要将相同的数据插入到日志
表中。

T_TAR

T_ORG

T_LOG

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER

CREATE OR REPLACE TRIGGER T_INSERT_TAR


AFTER INSERT ON T_TAR
FOR EACH ROW
BEGIN
INSERT INTO T_LOG (ID, NAME)
VALUES (:NEW.ID, :NEW.NAME);
END;
/
云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
• 太“重”
• 实现与需求有差异
• 增加后续维护成本
• 触发器效率较低

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT

INSERT INTO T_TAR SELECT * FROM T_ORG;


INSERT INTO T_LOG SELECT * FROM T_ORG;

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
• 一致性
➢ 锁
➢ 串行事务
➢ 临时表
➢ AS OF查询
• 原子性
➢ 异常处理

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
⚫ OPEN CURSOR
SQL> BEGIN
2 FOR I IN (SELECT * FROM T_ORG) LOOP
3 INSERT INTO T_TAR VALUES (I.ID, I.NAME);
4 INSERT INTO T_LOG VALUES (I.ID, I.NAME);
5 END LOOP;
6 END;
7 /

PL/SQL 过程已成功完成。
云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
⚫ OPEN CURSOR
⚫ 效率低

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
⚫ OPEN CURSOR
⚫ BULK INTO VARIABLE

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

SQL> DECLARE
2 TYPE T_ID IS TABLE OF T_ORG.ID%TYPE;
3 TYPE T_NAME IS TABLE OF T_ORG.NAME%TYPE;
4 V_ID T_ID;
5 V_NAME T_NAME;
6 BEGIN
7 SELECT ID, NAME BULK COLLECT INTO V_ID, V_NAME
8 FROM T_ORG;
9 FORALL I IN 1..V_ID.COUNT
10 INSERT INTO T_TAR VALUES(V_ID(I), V_NAME(I));
11 FORALL I IN 1..V_ID.COUNT
12 INSERT INTO T_LOG VALUES(V_ID(I), V_NAME(I));
13 END;
14 /

PL/SQL 过程已成功完成。

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
⚫ OPEN CURSOR
⚫ BULK INTO VARIABLE
• 复杂度高
• 效率较低

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

方案:
⚫ CREATE TRIGGER
⚫ DOUBLE INSERT
⚫ OPEN CURSOR
⚫ BULK INTO VARIABLE
⚫ INSERT ALL

SQL> INSERT ALL INTO T_TAR (ID, NAME)


2 INTO T_LOG (ID, NAME)
3 SELECT ID, NAME FROM T_ORG;

云和恩墨成就所托
云和恩墨 成就所托
WITH语句
列出T表中用户包含对象数量大于平均用户对象数的记录
SQL> SELECT OWNER, COUNT(*) CN
2 FROM T
3 GROUP BY OWNER
4 HAVING COUNT(*) >
5 (SELECT AVG(COUNT(*)) FROM T GROUP BY OWNER);

OWNER CN
------------------------------ ----------
PUBLIC 37071
SYS 42068

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 12 | 452 (2)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | HASH GROUP BY | | 2 | 12 | 452 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL | T | 91168 | 534K| 445 (1)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 6 | 452 (2)| 00:00:01 |
| 5 | SORT GROUP BY | | 1 | 6 | 452 (2)| 00:00:01 |
| 6 | TABLE ACCESS FULL| T | 91168 | 534K| 445 (1)| 00:00:01 |
-----------------------------------------------------------------------------
云和恩墨成就所托
云和恩墨 成就所托
WITH语句
SQL> WITH A AS
2 (SELECT OWNER, COUNT(*) CN FROM T GROUP BY OWNER)
3 SELECT A.*
4 FROM A, (SELECT AVG(CN) ACN FROM A) B
5 WHERE A.CN > B.ACN;

OWNER CN
------------------------------ ----------
PUBLIC 37071
SYS 42068

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 92 | 456 (2)|
| 1 | TEMP TABLE TRANSFORMATION | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6633_DE0CE4 | | | |
| 3 | HASH GROUP BY | | 26 | 156 | 452 (2)|
| 4 | TABLE ACCESS FULL | T | 91168 | 534K| 445 (1)|
| 5 | NESTED LOOPS | | 1 | 92 | 4 (0)|
| 6 | VIEW | | 1 | 13 | 2 (0)|
| 7 | SORT AGGREGATE | | 1 | 13 | |
| 8 | VIEW | | 26 | 338 | 2 (0)|
| 9 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6633_DE0CE4 | 26 | 156 | 2 (0)|
|* 10 | VIEW | | 1 | 79 | 2 (0)|
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6633_DE0CE4 | 26 | 156 | 2 (0)|
---------------------------------------------------------------------------------------------
云和恩墨成就所托
云和恩墨 成就所托
ANALYTIC FUNCTIONS
以用户名和对象名称来判断重复记录,列出重复的记录:
SQL> SELECT OWNER, OBJECT_NAME
2 FROM T
3 WHERE OWNER = 'TEST'
4 AND ROWID NOT IN (
5 SELECT MAX(ROWID)
6 FROM T
7 WHERE OWNER = 'TEST'
8 GROUP BY OWNER, OBJECT_NAME)
9 ORDER BY 1, 2;

OWNER OBJECT_NAME
------------------------------ ----------------------------------------
TEST T_PART
TEST T_PART
TEST T_PART
TEST T_PART
……
TEST T_PART2
TEST T_PART2

云和恩墨成就所托
云和恩墨 成就所托
ANALYTIC FUNCTIONS
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2644 | 139K| 808 (1)| 00:00:01 |
| 1 | SORT ORDER BY | | 2644 | 139K| 808 (1)| 00:00:01 |
|* 2 | HASH JOIN RIGHT ANTI| | 2644 | 139K| 807 (1)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1891 | 22692 | 404 (1)| 00:00:01 |
| 4 | HASH GROUP BY | | 1891 | 79422 | 404 (1)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| T | 2697 | 110K| 403 (1)| 00:00:01 |
|* 6 | TABLE ACCESS FULL | T | 2697 | 110K| 403 (1)| 00:00:01 |
----------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2902 consistent gets
0 physical reads
0 redo size
3015 bytes sent via SQL*Net to client
611 bytes received via SQL*Net from client
10 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
132 rows processed

云和恩墨成就所托
云和恩墨 成就所托
ANALYTIC FUNCTIONS
SQL> SELECT OWNER, OBJECT_NAME
2 FROM (
3 SELECT OWNER, OBJECT_NAME,
4 ROW_NUMBER() OVER(PARTITION BY OWNER, OBJECT_NAME ORDER BY ROWID DESC) RN
5 FROM T
6 WHERE OWNER = 'TEST')
7 WHERE RN > 1
8 ORDER BY 1, 2;

OWNER OBJECT_NAME
------------------------------ ----------------------------------------
TEST T_PART
TEST T_PART
TEST T_PART
TEST T_PART
……
TEST T_PART2
TEST T_PART2

云和恩墨成就所托
云和恩墨 成就所托
ANALYTIC FUNCTIONS
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2697 | 252K| 404 (1)| 00:00:01 |
|* 1 | VIEW | | 2697 | 252K| 404 (1)| 00:00:01 |
| 2 | WINDOW SORT | | 2697 | 110K| 404 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T | 2697 | 110K| 403 (1)| 00:00:01 |
----------------------------------------------------------------------------

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1451 consistent gets
0 physical reads
0 redo size
3015 bytes sent via SQL*Net to client
611 bytes received via SQL*Net from client
10 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
132 rows processed

云和恩墨成就所托
云和恩墨 成就所托
TOP-N语句

按照对象ID排序,取第21条到30条记录:
SQL> SELECT OBJECT_ID, OBJECT_NAME FROM
2 (SELECT ROWNUM RN, A.* FROM
3 (SELECT OBJECT_ID, OBJECT_NAME FROM T
4 ORDER BY OBJECT_ID) A
5 WHERE ROWNUM <= 30)
6 WHERE RN > 20;

OBJECT_ID OBJECT_NAME
---------- ----------------------------------------------
22 USER$
23 PROXY_DATA$
24 I_PROXY_DATA$
25 PROXY_ROLE_DATA$
26 I_PROXY_ROLE_DATA$_1
27 I_PROXY_ROLE_DATA$_2
28 CON$
29 C_COBJ#
30 I_COBJ#
31 CDEF$

云和恩墨成就所托
云和恩墨 成就所托
TOP-N语句

SQL> SELECT OBJECT_ID, OBJECT_NAME FROM


2 (SELECT ROW_NUMBER() OVER(ORDER BY OBJECT_ID) RN, OBJECT_ID, OBJECT_NAME
3 FROM T)
4 WHERE RN <= 30
5 AND RN > 20;

OBJECT_ID OBJECT_NAME
---------- ----------------------------------
22 USER$
23 PROXY_DATA$
24 I_PROXY_DATA$
25 PROXY_ROLE_DATA$
26 I_PROXY_ROLE_DATA$_1
27 I_PROXY_ROLE_DATA$_2
28 CON$
29 C_COBJ#
30 I_COBJ#
31 CDEF$

云和恩墨成就所托
云和恩墨 成就所托
TOP-N语句

SQL> SELECT OBJECT_ID, OBJECT_NAME FROM T


2 ORDER BY OBJECT_ID
3 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

OBJECT_ID OBJECT_NAME
---------- -----------------------------------------------------------------------------
22 USER$
23 PROXY_DATA$
24 I_PROXY_DATA$
25 PROXY_ROLE_DATA$
26 I_PROXY_ROLE_DATA$_1
27 I_PROXY_ROLE_DATA$_2
28 CON$
29 C_COBJ#
30 I_COBJ#
31 CDEF$

云和恩墨成就所托
云和恩墨 成就所托
合理运用新特性

新特性:
⚫ INSERT ALL/ANY 插入多张表或限定条件插入
⚫ MERGE 合并UPDATE和INSERT语句
⚫ WITH 避免重复读取
⚫ ANALYTIC FUNCTIONS 行级计算避免自关联
⚫ TOP-N 分页语句
⚫ PIVOT/UNPIVOT 行列转换
⚫ MODEL 报表数组处理
⚫ PATTERN 模式匹配查询

云和恩墨成就所托
云和恩墨 成就所托
云和恩墨成就所托
云和恩墨 成就所托 云和恩墨 成就所托

You might also like