sql 调优有哪些技巧

你好

我从几个方面受益于本网站。 我想与大家分享一些SQL调优技术(简单但有效)。

SQL调优技巧 Oracle技巧会议#6 3/31/98 Kathy Gleeson

________________________________________

SQL是Oracle系统的心脏。 您可以使用许多不同SQL语句来达到相同的结果。 在通常情况下,在给定情况下,只有一个语句是最有效的选择。 下面的技巧包括有关一种形式的语句是否总是效率更高或每种语句是否可以替代的信息,并且效率会根据您的应用程序而有所不同。

Oracle分两个步骤处理SQL:解析和执行。 调优可以通过减少解析,执行或同时减少两者来加快SQL的速度。 请注意,仅在代码正常工作后才能进行SQL调整。 请注意,编写高效SQL与可理解SQL之间不可避免地会发生拔河。

提示1(最佳技巧):除非SQL完全相同,否则无法在Oracle中共享SQL。 语句必须完全匹配,以防在Oracle内存中共享大小写和基础架构对象。 Oracle避免在以后每次使用相同的语句时进行解析。

sql>从ID为212的S_CUSTOMER中选择名称; 符合条件的陈述

sql>从s_customer中选择名称WHERE ID = 212; 小写

sql>从S_CUSTOMER WHERE ID = 212中选择名称; 空格

sql>选择名称

来自S_CUSTOMER

WHERE ID = 212; 空格

o在应用程序中使用SQL标准。 像下面这样的规则很容易实现,并且将允许在Oracle内存中进行更多共享。

-对所有SQL动词使用一种情况

-在所有行上开始所有SQL动词

-初始SQL动词内的左右对齐动词

-用单个空格分隔所有单词

o使用绑定变量。 对于两个被视为相同的语句,绑定变量的值不必相同。 在成功解析语句之前,不会替换绑定变量。

可共享SQL

选择*从emp哪里emp_no =:B1; 绑定值:123

选择*从emp哪里emp_no =:B1; 绑定值:987

不可共享SQL

选择*从emp WHERE emp_no = 123;

选择*从emp哪里emp_no = 987;

o使用标准方法来表别名。 如果两个相同SQL语句由于相同的表具有两个不同的别名而有所不同,则该SQL是不同的,将不会共享。

o使用表别名,并在查询中涉及多个表时,为所有列名加上别名前缀。 如果有人将一个列添加到与另一个表中的列同名的表中,这会减少解析时间并防止将来出现语法错误。 (ORA-00918:歧义定义的列)

提示2:提防根本不使用索引的WHERE子句。 即使本节中包含的WHERE子句引用的列上有索引,Oracle也会忽略该索引。 所有这些WHERE子句都可以重写为使用索引,同时返回相同的值。 换句话说,不要对WHERE子句中引用的数据库对象执行操作。

请勿使用

  1.  
     
  2.  
    SELECT account_name, trans_date, amount 
  3.  
    FROM transaction 
  4.  
    WHERE SUBSTR(account_name,1,7) = 'CAPITAL';     
  5.  
    SELECT account_name, trans_date, amount 
  6.  
    FROM transaction 
  7.  
    WHERE account_name LIKE 'CAPITAL%'; 
  8.  
    SELECT account_name, trans_date, amount 
  9.  
    FROM transaction 
  10.  
    WHERE account_name = NVL ( :acc_name, account_name);     
  11.  
    SELECT account_name, trans_date, amount 
  12.  
    FROM transaction 
  13.  
    WHERE account_name LIKE NVL ( :acc_name, '%'); 
  14.  
    SELECT account_name, trans_date, amount 
  15.  
    FROM transaction 
  16.  
    WHERE TRUNC (trans_date) = TRUNC (SYSDATE);     
  17.  
    SELECT account_name, trans_date, amount 
  18.  
    FROM transaction 
  19.  
    WHERE trans_date BETWEEN TRUNC (SYSDATE) AND TRUNC (SYSDATE) + .99999; 
  20.  
    SELECT account_name, trans_date, amount 
  21.  
    FROM transaction 
  22.  
    WHERE account_name || account_type = 'AMEXA';     
  23.  
    SELECT account_name, trans_date, amount 
  24.  
    FROM transaction 
  25.  
    WHERE account_name = 'AMEX' 
  26.  
    AND account_type = 'A'; 
  27.  
    SELECT account_name, trans_date, amount 
  28.  
    FROM transaction 
  29.  
    WHERE amount + 3000 < 5000;     
  30.  
    SELECT account_name, trans_date, amount 
  31.  
    FROM transaction 
  32.  
    WHERE amount < 2000; 
  33.  
    SELECT account_name, trans_date, amount 
  34.  
    FROM transaction 
  35.  
    WHERE amount != 0;     
  36.  
    SELECT account_name, trans_date, amount 
  37.  
    FROM transaction 
  38.  
    WHERE amount > 0; 
  39.  
    SELECT account_name, trans_date, amount 
  40.  
    FROM transaction 
  41.  
    WHERE amount NOT = 0;     
  42.  
    SELECT account_name, trans_date, amount 
  43.  
    FROM transaction 
  44.  
    WHERE amount > 0; 

提示3:不要忘记调整视图。 视图是SELECT语句,可以通过与其他任何类型的SELECT语句相同的方式进行调整。 适用于任何SQL语句的所有调整都同样适用于视图。

提示4:避免在SELECT语句中包含HAVING子句。 仅在获取所有行之后,HAVING子句才会过滤选定的行。 使用WHERE子句有助于减少排序,求和等方面的开销。仅当对其应用了汇总操作的列受该子句限制时,才应使用HAVING子句。

请勿使用

  1.  
     
  2.  
    SELECT region, AVG (loc_size) 
  3.  
    FROM location 
  4.  
    GROUP BY region 
  5.  
    HAVING region != 'SYDNEY' 
  6.  
    AND region != 'PERTH';     
  7.  
    SELECT region, AVG (loc_size) 
  8.  
    FROM location 
  9.  
    WHERE region != 'SYDNEY' 
  10.  
    AND region != 'PERTH'; 
  11.  
    GROUP BY region; 

提示5:最小化查询中的表查找(子查询块)的数量,尤其是在您的语句包含子查询SELECT或多列UPDATE的情况下。

单独的子查询

  1.  
     
  2.  
    SELECT emp_name 
  3.  
    FROM emp 
  4.  
    WHERE emp_cat = (SELECT MAX (category) 
  5.  
    FROM emp_categories) 
  6.  
    AND emp_range = (SELECT MAX (sal_range) 
  7.  
    FROM emp_categories) 
  8.  
    AND emp_dept = 0020; 

组合子查询

  1.  
     
  2.  
    SELECT emp_name 
  3.  
    FROM emp 
  4.  
    WHERE (emp_cat, sal_range) 
  5.  
    = (SELECT MAX (category), MAX (sal_range) 
  6.  
    FROM emp_categories) 
  7.  
    AND emp_dept = 0020; 

提示6:进行多个表联接时,请考虑选择EXISTS,IN和表联接。 这些都不是一直更快的。 这取决于您的数据。 如果此处的绩效不佳,则可能是IN子句。

(注意,此查询返回部门类别“ A”中每个部门的员工姓名。)

  1.  
     
  2.  
    SELECT emp_name 
  3.  
    FROM emp E 
  4.  
    WHERE EXISTS ( SELECT 'X' 
  5.  
    FROM dept 
  6.  
    WHERE dept_no = E.dept_no 
  7.  
    AND dept_cat = 'A');
  8.  
    SELECT emp_name 
  9.  
    FROM emp E 
  10.  
    WHERE dept_no IN ( SELECT dept_no 
  11.  
    FROM dept 
  12.  
    WHERE dept_no = E.dept_no 
  13.  
    AND dept_cat = 'A');
  14.  
    SELECT emp_name 
  15.  
    FROM dept D, emp E 
  16.  
    WHERE E.dept_no = D.dept_no 
  17.  
    AND D.dept_cat = 'A'; 

提示7:在用于确定一对多关系所有者端信息的查询中,避免在SELECT列表上使用要求DISTINCT限定符的联接。 DISTINCT运算符使Oracle提取满足表联接的所有行,然后对重复的值进行排序和过滤。 EXISTS是一种更快的替代方法,因为Oracle优化器意识到一旦满足了子查询,就无需进一步进行操作并且可以提取下一个匹配的行。

(注意:此查询返回至少有一名雇员的所有部门编号和名称。)

  1.  
     
  2.  
    Do Not Use    Use
  3.  
    SELECT DISTINCT dept_no, dept_name 
  4.  
    FROM dept D, 
  5.  
    emp E 
  6.  
    WHERE D.dept_no = E.dept_no;    SELECT dept_no, dept_name 
  7.  
    FROM dept D 
  8.  
    WHERE EXISTS ( 
  9.  
    SELECT 'X' 
  10.  
    FROM emp E 
  11.  
    WHERE E.dept_no = D.dept_no); 

提示8:考虑使用UNION ALL代替UNION是否足够。 UNION子句强制在返回第一行之前,对UNION的每个部分返回的所有行进行排序和合并,并对重复项进行过滤。 UNION ALL仅返回所有包含重复项的行,而不必执行任何排序,合并或过滤。 如果您的表是互斥的(不包括重复的记录),或者您不在乎是否返回重复项,那么UNION ALL效率会更高。

联合所有

  1.  
     
  2.  
    SELECT acct_num, balance_amt 
  3.  
    FROM debit_transactions 
  4.  
    WHERE tran_date = '31-DEC-95' 
  5.  
    UNION 
  6.  
    SELECT acct_num, balance_amt 
  7.  
    FROM credit_transactions 
  8.  
    WHERE tran_date = '31-DEC-95';     
  9.  
    SELECT acct_num, balance_amt 
  10.  
    FROM debit_transactions 
  11.  
    WHERE tran_date = '31-DEC-95' 
  12.  
    UNION ALL 
  13.  
    SELECT acct_num, balance_amt 
  14.  
    FROM credit_transactions 
  15.  
    WHERE tran_date = '31-DEC-95'; 

提示9:考虑使用DECODE避免重复扫描相同的行或重复连接同一表。 请注意,DECODE不一定更快,因为它取决于您的数据和结果查询的复杂性。 另外,使用DECODE要求您在字段中允许新值时更改代码。

  1.  
     
  2.  
    SELECT COUNT(*) 
  3.  
    FROM emp 
  4.  
    WHERE status = 'Y' 
  5.  
    AND emp_name LIKE 'SMITH%'; 
  6.  
    ---------- 
  7.  
    SELECT COUNT(*) 
  8.  
    FROM emp 
  9.  
    WHERE status = 'N' 
  10.  
    AND emp_name LIKE 'SMITH%';
  11.  
    SELECT COUNT(DECODE(status, 'Y', 'X', NULL)) Y_count, 
  12.  
    COUNT(DECODE(status, 'N', 'X', NULL)) N_count 
  13.  
    FROM emp 
  14.  
    WHERE emp_name LIKE 'SMITH%'; 

提示10:Oracle在比较不同类型的列时会自动执行简单的列类型转换(或转换)。 根据转换类型的不同,可能不使用索引。 如果您使用的编程语言支持该类型,请确保将程序变量声明为与Oracle列相同的类型。

数据类型

哪里

子句隐式转换索引后的查询

用过的?

emp_no

索引

数字SELECT ...

来自emp

WHERE emp_no ='123'; 选择 ...

来自emp

在哪里emp_no = TO_NUMBER('123'); 是

emp_type

索引

varchar2 SELECT ...

来自emp

WHERE emp_type = 123; 选择 ...

来自emp

在哪里TO_NUMBER(emp_type)= 123; 没有!

________________________________________

翻译自: https://bytes.com/topic/oracle/insights/658579-sql-tuning-tricks

(本文是转载自某大佬= =)

posted @ 2020-12-17 22:21  KhazixW2  阅读(150)  评论(0编辑  收藏  举报