Xpert 调优

-- 10046 event 可以定义 SQL TRACE 级别
/*
|| 默认的10046级别跟 SQL TRACE 一样, 另外还有一些级别:
|| level 1: SQL Tracing
|| level 4: Tracing with bind variable values
|| level 8: Tracing with wait events
|| level 12 Tracing with bind variables and wait events (4+8=12)

level 4, 12 可以看到绑定变量的值.
*/

alter session set events '10046 trace name context forever, level 4';
-- 关闭 10046, 只需要将 level 设置成 0

-- If you wish to set the 10046 event in another user's session,
-- you will need to use the DBMS_SYSTEM, The SET_EV procedure can set an event in any session
-- You will need the SID and SERIAL# of that session from V$SESSION.
-- example:
exec dbms_system.set_ev(sid,serial#,10046,12,'');

-- 另外要使用 TKPROF 来查看 trace file 生成的报告, 直接看 trace file 无法看懂
10046 event
-- Program data instantiated within a program is stored in PGA for each user, rather than in the SGA
-- 执行pl/sql程度的相关数据, 存储在PGA中, 被编译好的PL/SQL程序本身是共享的.
-- This means that each user has his own copy of program data. If a procedure declares a PL/SQL table
-- and fills it full of 1000 strings, every user who executes that procedure has his own copy of that table and its 1000 
-- strings. This characteristic does however provide you with a fair amount of flexibility 
-- to finding the delicate resource balance between CPU and memory.

-- 权限问题
-- Stored code runs under the authority of that code’s owner, not that of the schema which is executing the code. 
-- 也就是说, 存储过程执行时是创建存储过程那个用户的权限.
-- Even though stored code runs under the authority of that code’s owner, the USER function still 
-- returns the name of the schema currently connected to Oracle.

-- 执行 procedure
-- sqlplus 环境, execute calc_totals 或 exec calc_totals
-- 如果是匿名的, 直接就执行了, 比如
begin
    calc_totals;
end;

-- 执行 function, 因为 function 有返回值, 所以, 它不能直接执行, 要有个类似变量来接收函数返回值.
-- 直接执行, 可以类似这种
exec DBMS_OUTPUT.PUT_LINE (total_sales (1997))

-- 远程调用
schema_name.[package_name.]module_name@database_link_name
emp_name := full_name@new_york (:emp.employee_id);
basic
-- sql*plus 提供的session变量
-- session variable , 可以使用的数据类型 varchar2, varchar2(N), char
-- number, number(N)

varibale X varchar2(10)
EXECUTE :X := '123';
PRINT X
session varibale
-- Because stored objects are contained in tables in the data dictionary, you can use SQL itself to get information 
-- about the currently available programs. The following views are the most useful to familiarize yourself with:

/*
USER_DEPENDENCIES - The dependencies to and from objects you own
USER_ERRORS - The current set of errors for all stored objects you own.
USER_OBJECTS - The objects you own
USER_OBJECT_SIZE - The size of the objects you own
USER_SOURCE - The text source code for all objects you own
USER_TRIGGER - The database triggers you own 
*/

-- USER_DEPENDENCIES
-- Use the USER_DEPENDENCIES view to see which objects reference or depend on a particular object
SELECT referenced_name, 
       referenced_type, 
       referenced_owner, 
       referenced_link_name
  FROM user_dependencies
 WHERE name = UPPER ('&1');

-- USER_OBJECTS
-- Displaying Information About Stored Objects, 3列比较重要 OBJECT_NAME, OBJECT_TYPE, STATUS
SET PAGESIZE 66
COLUMN object_type FORMAT A20
COLUMN object_name FORMAT A30
COLUMN status FORMAT A10
BREAK ON object_type SKIP 1
SPOOL psobj.lis
SELECT object_type, object_name, status
  FROM user_objects
 WHERE object_type IN ('PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'PROCEDURE')
 ORDER BY object_type, status, object_name
/
SPOOL OFF

-- USER_OBJECT_SIZE
-- tell you about the size of your code
SET PAGESIZE 66
COLUMN name FORMAT A30
COLUMN type FORMAT A15
COLUMN source_size FORMAT 999999
COLUMN parsed_size FORMAT 999999
COLUMN code_size FORMAT 999999
TTITLE 'Size of PL/SQL Objects > 2000 Bytes'
SPOOL pssize.lis
SELECT name, type, source_size, parsed_size, code_size
  FROM user_object_size
 WHERE code_size > 2000
 ORDER BY code_size DESC
/
SPOOL OFF

-- USER_SOURCE
-- You should always maintain the source code of your programs in text files (or a development tool specifically designed
-- to store and manage PL/SQL code outside of the database).I
SELECT text 
  FROM user_source 
 WHERE name = UPPER ('&1') 
 ORDER BY line;
Check Object
-- 1. 选择驱动表, 多表连接时
-- When Oracle processes multiple tables, it must join the two tables. 
--  There are four different join methods in the Oracle database, 
-- the Nested Loop Join, the Sort-Merge Join, the Hash Join, and the Cartesian Join
-- Cartesian Join : 笛卡尔积连接
-- Sort-Merge Join: has a sort phase and a merge phase, it scans and sorts the first (driving) 
--                   table (the one specified second in the FROM clause). Next, it scans the second
--                    table (the one specified first in the FROM clause) and merges all of the rows
--                    retrieved from the second table with those retrieved from the first table.
-- Nested Loop Join: every row in the driving table and then finds matches in the second table.
--                    If there is no index on the join column, a full table scan is performed on
--                    the second table for every row in the driving table.
--                    这种的话, 如果主驱动表100W列, 而另一个表只有10列的话, 肯定是将只有10列的表设置为
--                    主驱动表比较好
-- Hash Join:     uses a hashing algorithm (hence its name) to divide the driving table's rows into
--                multiple buckets. The second table is hashed with the same algorithm.
-- 注意: 主驱动表是  is the second table in the FROM clause of the SQL statement.
-- 例如:
/*
Table TAB1  has 16,384   rows.
Table TAB2  has 4        rows.
*/
SELECT COUNT (*) FROM TAB1, TAB2         -- 4.00 seconds elapsed
                     count     phys      cr        cur      rows
                     ------    -----    -----     -----    ------
        Parse          1         0      0         0
        Execute        1         384    386       10         0
        Fetch          1         0      0         0          1

SELECT COUNT (*) FROM TAB2, TAB1 -- 37.32 seconds elapsed
                     count     phys      cr        cur      rows
                     ------    -----    -----     -----    ------
        Parse          1         0      0         0
        Execute        1         95     49247     32770      0
        Fetch          1         0      0         0          1

-- 多表查询join 时, 选择几个表之间的交集的那个表作为驱动表.
-- 多表时, 貌似 from 后的第一个表是驱动表, 或者通过交集? 看下边例子
SELECT   . . .
FROM     location L,
         category C,
         emp E
  WHERE  E.emp_no BETWEEN 1000 AND 2000
    AND  E.cat_no =  C.cat_no
    AND  E.locn   =  L.locn
-- 更高效的做法
SELECT     . . .
 FROM      emp E,
           location L,
           category C
    WHERE  E.cat_no =  C.cat_no
      AND  E.locn   =  L.locn
      AND  E.emp_no BETWEEN 1000 AND 2000
调优法则
-- 1. 高效的删除重复的行 #################################
DELETE FROM emp E
      WHERE E.rowid > (SELECT MIN(X.rowid)
                            FROM emp X
                           WHERE X.emp_no = E.emp_no);

-- 2. 一般情况下, 在列上有索引时, 选择使用 IN 或 UNION 比 OR 更好. #################################
SELECT . . .                     SELECT . . .
   FROM   location                  FROM   location
   WHERE  loc_id = 10               WHERE  loc_id = 10
   OR     region = 'MELBOURNE'      OR     loc_id = 20
                                    OR     loc_id = 30
-- 改进:
SELECT . . .                     SELECT . . .
   FROM   location                  FROM   location
   WHERE  loc_id = 10               WHERE  loc_in IN (10,20,30)
   UNION
   SELECT . . .
   FROM   location
   WHERE  region = 'MELBOURNE'

-- 3. 最小化表扫描 minimize the number of table lookups (subquery blocks) in queries, 例如: ##########
SELECT emp_name
FROM   emp
WHERE  emp_cat   = ( SELECT MAX(category)
                        FROM   emp_categories )
AND    sal_range = ( SELECT MAX(sal_range)
                        FROM   emp_categories )
AND    emp_dept  = 0020;
-- 上例中, 两个子查询是分开的, 那么需要独立扫描两次, 改进如下:
SELECT emp_name
FROM   emp
WHERE (emp_cat, sal_range)
                    = ( SELECT MAX(category), MAX(sal_range)
                        FROM   emp_categories )
AND    emp_dept  = 0020;
-- 修改的时候也一样, 参考下例:
UPDATE emp
SET    emp_cat   = ( SELECT MAX(category)
                     FROM   emp_categories ),
       sal_range = ( SELECT MAX(sal_range)
                     FROM   emp_categories )
WHERE  emp_dept  = 0020;
-- 改进
UPDATE emp
SET   (emp_cat, sal_range)
                 = ( SELECT MAX(category), MAX(sal_range)
                     FROM   emp_categories )
WHERE  emp_dept  = 0020;

-- 4. not exists 与 not in 的比较 not exists 好 ########################################
SELECT . . .
FROM   emp
WHERE  dept_no NOT IN ( SELECT dept_no
                           FROM   dept
                           WHERE  dept_cat = 'A');
-- 改进
SELECT . . .
FROM   emp E
WHERE  NOT EXISTS ( SELECT  'X'
                       FROM   dept
                       WHERE  dept_no  = E.dept_no
                       AND    dept_cat = 'A'   );
-- 5. reduce database access
-- 例如: 低效, 分别两次访问 database
SELECT emp_name, salary, grade
FROM    emp
WHERE  emp_no = 0342;

SELECT emp_name, salary, grade
FROM    emp
WHERE  emp_no = 0291;
-- 改进, 一次访问数据库
SELECT   emp_name, salary, grade,
FROM     emp A
WHERE    emp_no IN (0342,0291) ;

-- 6. 使用 * 时, 最好给表起个别名, 然后使用, 这样高效, 例如 ####################################
INSERT INTO emp_audit
SELECT USER, SYSDATE, A.*
FROM   emp A
WHERE  emp_no = :emp_no;

-- 7. union 和 union all
-- 一般如果不考虑去掉 重复的, 还有排序等内容的话, 使用 union all

-- 8. decode 可以被活用, 例如:
SELECT COUNT(*), SUM(salary)
FROM   emp
WHERE  dept_no  =  0020
AND    emp_name LIKE 'SMITH%' ;

SELECT COUNT(*), SUM(salary)
FROM   emp
WHERE  dept_no  =  0030
AND    emp_name LIKE 'SMITH%' ;
-- 改进
SELECT COUNT(DECODE(dept_no, 0020, 'X',    NULL)) D0020_kount,
       COUNT(DECODE(dept_no, 0030, 'X',    NULL)) D0030_kount,
       SUM  (DECODE(dept_no, 0020, salary, NULL)) D0020_sal,
       SUM  (DECODE(dept_no, 0030, salary, NULL)) D0030_sal
 FROM  emp
WHERE  emp_name LIKE 'SMITH%';
一般SQL调优

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值