首页 生活指南 正文内容

1.共享SQL语句执行步骤>语义分析(组图)

阿立指南 生活指南 2022-09-27 22:09:31 514 0

oracle数据库优化方法_oracle数据库优化方法_oracle优化方法

oracle优化方法_oracle数据库优化方法_oracle数据库优化方法

1. SQL 语句执行步骤

语法分析 > 语义分析 > 视图转换 > 表达式转换 > 选择优化器 > 选择连接方法 > 选择连接顺序 > 选择数据搜索路径 > 运行“执行计划”

2. 选择合适的优化器 RULE(基于规则)、COST(基于成本)、(可选)

3. 访问表的方法 全表扫描 全表扫描是按顺序访问表中的每条记录,通过一次读取多个数据块来优化全表扫描。通过ROWID访问表 ROWID包含了表中记录的物理位置信息,并通过索引实现了数据与存储数据的物理位置(ROWID)的连接。通常,索引提供了一种快速访问ROWID的方法,因此那些基于索引列的查询可以在性能上得到提升。

4. 共享 SQL 语句

5. 选择最高效的表名序列 示例:表 TAB1 16,384 条记录 表 TAB2 1 条记录

/*选择TAB2作为基础表 (最好的方法)*/SELECT COUNT(*) FROM TAB1,TAB2/*执行时间0.96秒*/
/*选择TAB1作为基础表 (不佳的方法)*/SELECT COUNT(*) FROM TAB2,TAB1 /*执行时间26.09秒*/

如果要加入查询的表超过3张,则需要选择交叉表(表)作为基表,交叉表是指被其他表引用的表。

/*高效的SQL*/SELECT * FROM LOCATION L, CATEGORY C, EMP E WHERE E.EMP_NO BETWEEN 1000 AND 2000AND E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCN

会比下面的 SQL 更高效

/*低效的SQL*/SELECT * FROM EMP E, LOCATION L, CATEGORY CWHERE E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCNAND E.EMP_NO BETWEEN 1000 AND 2000


6. Where 子句中的连接顺序以自下而上或从右到左的顺序解析 WHERE 子句。根据这个原则,表之间的连接必须写在其他 WHERE 条件之前,而那些可以过滤掉最大记录数的条件必须写在 WHERE 子句的末尾。

/*低效,执行时间156.3秒*/SELECT Column1,Column2FROM EMP EWHERE E.SAL > 50000AND E.JOB = 'MANAGER'AND 25 < (SELECT COUNT(*) FROM EMPWHERE MGR = E.EMPNO)

/*高效,执行时间10.6秒*/SELECT Column1,Column2FROM EMP EWHERE 25 < (SELECT COUNT(*) FROM EMPWHERE MGR=E.EMPNO)AND E.SAL > 50000AND E.JOB = 'MANAGER'

避免在 7. 子句中使用“*”

8. 减少数据库访问次数 在每条SQL语句执行的时候,内部都做了很多工作:解析SQL语句>估计索引的利用率>绑定变量>读取数据块等。可以是看到减少访问数据库的次数,实际上可以减少工作量。

9. 整个简单的无关数据库访问如果有几个简单的数据库查询语句,可以将它们组合成一个查询(即使它们之间没有关系),以减少过多的数据库IO开销。这种方法虽然提高了效率,但是程序的可读性大大降低,所以还是要权衡利弊。

10. 使用代替

11.尽可能多的使用尽可能多的在程序中使用,这样可以提高程序的性能,由于资源的释放而减少需求。发布的资源:

12. 统计记录数

Select count(*) from tablename; Select count(1) from tablename; Select count(column) from tablename;

一般认为,在没有主键索引的情况下,第二种 COUNT(1) 方法最快。如果只有一列,没有索引,COUNT(*) 更快。如果有索引列,当然,使用索引列 COUNT() 是最快的。

13. 将该子句替换为Where子句,避免该子句,只有在检索到所有记录后才过滤结果集。这种处理需要进行排序、求和等操作。可以通过 WHERE 子句限制记录的数量来减少这种开销。

14.减少对表的查询操作在包含子查询的SQL语句中,注意减少对表的查询操作。

/*低效SQL*/SELECT TAB_NAME FROM TABLESWHERE TAB_NAME =(SELECT TAB_NAME FROM TAB_COLUMNSWHERE VERSION = 604)AND DB_VER =(SELECT DB_VER FROM TAB_COLUMNSWHERE VERSION = 604)

/*高效SQL*/SELECT TAB_NAME FROM TABLESWHERE (TAB_NAME,DB_VER)=(SELECT TAB_NAME,DB_VERFROM TAB_COLUMNSWHERE VERSION = 604)

15. 使用表别名(Alias) 在一条SQL语句中连接多个表时,请使用表别名,并在每张表前加上别名。这将减少解析时间并减少那些由歧义引起的语法错误。歧义是指由于 SQL 中不同的表同名,当 SQL 语句中出现 this 时,SQL 解析器无法确定 this 的归属。

16. 使用代替IN 在很多基于底层表的查询中,为了满足一个条件,往往需要连接另一个表。在这种情况下,使用(或 NOT )通常会提高查询的效率。

/*低效SQL*/SELECT * FROM EMP WHERE EMPNO > 0AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = 'MELB')

/*高效SQL*/SELECT * FROM EMPWHERE EMPNO > 0AND EXISTS (SELECT 1FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNOAND LOC = 'MELB')

17. 使用NOT代替NOT IN 在子查询中,NOT IN子句会进行内部排序和合并,对子查询中的表进行全表遍历,效率非常低。为了避免使用 NOT IN,可以将其重写为 Outer Joins 或 NOT。

/*低效SQL*/SELECT * FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT='A')

/*高效SQL*/SELECT * FROM EMP EWHERE NOT EXISTS (SELECT 1FROM DEPT DWHERE D.DEPT_NO = E.DEPT_NOAND DEPT_CAT ='A')

18. 用表连接代替表连接通常比表连接更有效。

/*低效SQL*/SELECT ENAMEFROM EMP EWHERE EXISTS (SELECT 1FROM DEPTWHERE DEPT_NO = E.DEPT_NOAND DEPT_CAT = 'A')

/*高效SQL*/SELECT ENAMEFROM DEPT D,EMP EWHERE E.DEPT_NO = D.DEPT_NOAND D.DEPT_CAT = 'A'

19. 在提交包含多个表(例如部门表和员工表)信息的查询时,被替换为避免使用 in 子句。一般来说,您可以考虑将其替换为 EXIST。使查询更快,因为 RDBMS 核心模块会在子查询条件满足时立即返回结果。

/*低效SQL*/SELECT DISTINCT D.DEPT_NO,D.DEPT_NAMEFROM DEPT D,EMP EWHERE D.DEPT_NO = E.DEPT_NO

/*高效SQL*/SELECT D.DEPT_NO,D.DEPT_NAMEFROM DEPT DWHERE EXISTS (SELECT 1FROM EMP EWHERE E.DEPT_NO = D.DEPT_NO)

20. 识别低效SQL 下列SQL 工具可以识别低效SQL,前提是需要DBA 权限,否则无法进行查询。

SELECT EXECUTIONS, DISK_READS, BUFFER_GETS,ROUND ((BUFFER_GETS-DISK_READS)/BUFFER_GETS, 2) Hit_radio,ROUND (DISK_READS/EXECUTIONS, 2) Reads_per_run, SQL_TEXTFROM V$SQLAREAWHERE EXECUTIONS>0AND  BUFFER_GETS > 0 AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8ORDER BY 4 DESC

此外,您还可以使用 SQL Trace 工具收集执行 SQL 的性能状态数据,包括解析次数、执行次数和 CPU 使用时间。

21. SQL with Plan Plan 是一个很好的分析SQL 语句的工具,它甚至可以在不执行SQL 的情况下分析语句。通过分析,我们可以知道如何连接表oracle数据库优化方法,使用如何扫描表(索引扫描或全表扫描)以及使用的索引名称。

22. SQL PLUS 的 TRACE

SQL> listSELECT *FROM dept, empWHERE emp.deptno = dept.deptnoSQL> set autotrace traceonly /*traceonly 可以不显示执行结果*/SQL> /rows selected.Execution Plan----------------------------------------------------------SELECT STATEMENT Optimizer=CHOOSE0 NESTED LOOPS1 TABLE ACCESS (FULL) OF 'EMP' 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'3 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)

23. 使用索引提高效率

(1)特点优点:提高效率主键唯一性验证成本:需要空间存储来定期维护和重建索引:

ALTER INDEX REBUILD

(2)索引有两种访问方式

(3)基表选择

(4)多个相等的索引

(5)等式比较优先于范围比较有一个非唯一索引,并且也有一个非唯一索引。

SELECT ENAME FROM EMPWHERE DEPTNO > 20AND EMP_CAT = 'A'

这里只使用了索引,那么所有的记录都会与条件一一进行比较。执行路径如下:

TABLE ACCESS BY ROWID ON EMPINDEX RANGE SCAN ON CAT_IDX

即使对于唯一索引,如果执行范围比较,其优先级也低于非唯一索引的相等比较。

(6)不明确的索引级别当无法判断索引的级别差异时,优化器将只使用一个索引,在WHERE子句中列在最前面。上面有一个非唯一索引,有也是一个非唯一索引。

SELECT ENAME FROM EMPWHERE DEPTNO > 20AND EMP_CAT > 'A'

这里只使用索引。执行路径如下:

TABLE ACCESS BY ROWID ON EMPINDEX RANGE SCAN ON DEPT_IDX

(7)强制索引无效如果两个或多个索引具有相同的排名,您可以强制优化器使用其中一个(通过它检索的记录更少)。

SELECT ENAMEFROM EMPWHERE EMPNO = 7935AND DEPTNO + 0 = 10 /*DEPTNO上的索引将失效*/AND EMP_TYPE || '' = 'A' /*EMP_TYPE上的索引将失效*/

(8)如果索引列是函数的一部分,请避免在索引列上使用计算的 WHERE 子句。优化器将使用全表扫描而不是索引。

/*低效SQL*/SELECT * FROM DEPTWHERE SAL * 12 > 25000;

/*高效SQL*/SELECT * FROM DEPTWHERE SAL > 25000/12;

(9)如果表中有两个以上(包括两个)索引,则自动选择索引,其中一个是唯一的,另一个是非唯一的。这种情况下,将使用唯一索引而不是完全忽略非唯一索​​引。

SELECT ENAME FROM EMP WHERE EMPNO = 2326AND DEPTNO = 20;

在这里,只有 EMPNO 上的索引是唯一的,所以 EMPNO 索引将用于检索记录。


TABLE ACCESS BY ROWID ON EMPINDEX UNIQUE SCAN ON EMP_NO_IDX

(10)避免在索引列上使用NOT 一般来说,我们希望避免在索引列上使用NOT,NOT与在索引列上使用函数的效果相同。当遇到NOT时,它会停止使用index 来执行全表扫描。

/*低效SQL: (这里,不使用索引)*/SELECT * FROM DEPTWHERE NOT DEPT_CODE = 0

/*高效SQL: (这里,使用索引)*/SELECT * FROM DEPTWHERE DEPT_CODE > 0

24. 如果有索引,则将 > 替换为 >=

/*高效SQL*/SELECT * FROM EMPWHERE DEPTNO >=4

/*低效SQL*/SELECT * FROM EMPWHERE DEPTNO >3

两者的区别在于前者的DBMS会直接跳转到DEPT等于4的第一条记录,而后者会先定位等于3的记录,然后向前扫描到DEPT大于3的第一条记录。

25. 将 OR 替换为 Union(对于索引列) 通常,将 WHERE 子句中的 OR 替换为 UNION 效果会更好。在索引列上使用 OR 将导致全表扫描。请注意,上述规则仅对多个索引列有效。

/*高效SQL*/SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10UNIONSELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE REGION = 'MELBOURNE'

/*低效SQL*/SELECT LOC_ID,LOC_DESC,REGIONFROM LOCATIONWHERE LOC_ID = 10OR REGION = 'MELBOURNE'

26. 用 IN 替换 OR

/*低效SQL*/SELECT * FROM LOCATIONWHERE LOC_ID = 10OR LOC_ID = 20OR LOC_ID = 30

/*高效SQL*/SELECT * FROM LOCATIONWHERE LOC_IN IN (10,20,30)

实际执行效果还有待测试。下面,两者的执行路径似乎是一样的。

27. 避免在索引列上使用is null 和is not null 避免在索引中使用任何可为空的列,索引将不起作用。

/*低效SQL:(索引失效)*/SELECT * FROM DEPARTMENTWHERE DEPT_CODE IS NOT NULL;

/*高效SQL:(索引有效)*/SELECT * FROM DEPARTMENTWHERE DEPT_CODE >=0;

28. 始终使用索引的第一列 如果索引建立在多列上,优化器将选择仅在 where 子句引用其第一列 ( ) 时使用该索引。

SQL> create index multindex on multiindexusage(inda,indb);Index created.
SQL> select * from multiindexusage where indb = 1;Execution Plan---------------------------------------------------------- SELECT STATEMENT Optimizer=CHOOSE0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE‘

显然,优化器使用了全表扫描,并在仅引用了索引的第二列时忽略了该索引。

29. 使用UNION ALL代替UNION 当SQL语句需要对两个查询结果集进行UNION时,两个结果集会以UNION-ALL的方式进行合并,然后进行排序后输出最终结果。如果使用 UNION ALL 代替 UNION,则不需要排序,提高效率。由于UNION ALL的结果没有排序oracle数据库优化方法,重复记录也没有过滤,所以是否替换取决于业务需求。

30. UNION的优化 由于UNION对查询结果进行排序,过滤重复记录,所以执行效率不如UNION ALL高。UNION操作会用到一块内存块,所以这块内存的优化也很重要。可以使用以下SQL查询排序的消耗:

select substr(name,1,25) "Sort Area Name",substr(value,1,15) "Value"from v$sysstatwhere name like 'sort%'

31. 避免改变索引列的类型

比较不同数据类型的数据时,会自动对列进行简单类型转换。

由于内部发生类型转换,将不会使用此索引。几点注意事项:

32. 使用提示 其他提示 这是一项棘手的工作。建议仅针对特定的少量 SQL 优化提示。

33.几个不能使用索引的WHERE子句(1)在下面的例子中,'!='不会使用索引,索引只能告诉你表中存在什么,不能告诉你什么不存在' t 存在于表中。

/*不使用索引*/SELECT ACCOUNT_NAMEFROM TRANSACTIONWHERE AMOUNT !=0;

/*使用索引*/SELECT ACCOUNT_NAMEFROM TRANSACTIONWHERE AMOUNT > 0;

(2)在下面的例子中,'||' 是一个字符连接函数。和其他函数一样,索引是禁用的。

/*不使用索引*/SELECT ACCOUNT_NAME,AMOUNTFROM TRANSACTIONWHERE ACCOUNT_NAME||ACCOUNT_TYPE='AMEXA';

/*使用索引*/SELECT ACCOUNT_NAME,AMOUNTFROM TRANSACTIONWHERE ACCOUNT_NAME = 'AMEX'AND ACCOUNT_TYPE='A';

(3)在下面的示例中,'+' 是一个数学函数。与其他数学函数一样,索引被禁用。

/*不使用索引*/SELECT ACCOUNT_NAME,AMOUNTFROM TRANSACTIONWHERE AMOUNT + 3000 >5000;

/*使用索引*/SELECT ACCOUNT_NAME,AMOUNTFROM TRANSACTIONWHERE AMOUNT > 2000 ;

(4)在下面的示例中,相同的索引列无法相互比较,这将启用全表扫描。

/*不使用索引*/SELECT ACCOUNT_NAME, AMOUNTFROM TRANSACTIONWHERE ACCOUNT_NAME = NVL(:ACC_NAME, ACCOUNT_NAME)

/*使用索引*/SELECT ACCOUNT_NAME,AMOUNTFROM TRANSACTIONWHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME, ’%’)

34. 加入多次扫描 如果将列与一组有限的值进行比较,优化器可能会执行多次扫描并合并结果。例子:

SELECT * FROM LODGING WHERE MANAGER IN ('BILL GATES','KEN MULLER')

优化器可能会将其转换为以下形式:

SELECT * FROM LODGINGWHERE MANAGER = 'BILL GATES'OR MANAGER = 'KEN MULLER'

35. 在CBO下使用更具选择性的索引

36. 避免资源密集型操作

37. 优化 GROUP BY,通过在 GROUP BY 之前过滤掉不必要的记录来提高 GROUP BY 语句的效率。

/*低效SQL*/SELECT JOB,AVG(SAL)FROM EMPGROUP BY JOBHAVING JOB = 'PRESIDENT''OR JOB = 'MANAGER'

/*高效SQL*/SELECT JOB,AVG(SAL)FROM EMPWHERE JOB = 'PRESIDENT'OR JOB = 'MANAGER'GROUP BY JOB

38. 使用日期 使用日期时要注意,如果日期加上小数点后5位以上,日期会提前到第二天!

SELECT TO_DATE('01-JAN-93'+.99999)FROM DUAL结果:'01-JAN-93 23:59:59'
SELECT TO_DATE('01-JAN-93'+.999999)FROM DUAL结果:'02-JAN-93 00:00:00'

39. 使用 show () 来使用隐式游标,它将执行两个操作。第一次检索记录,第二次检查 TOO MANY ROWS 这个。并且显式游标不执行第二个操作。

40. 分离表和索引 好了,关于SQL优化的内容,这篇文章应该可以满足大部分一般的应用优化需求。刚到这里。

oracle数据库优化方法_oracle优化方法_oracle数据库优化方法

直播

oracle优化方法_oracle数据库优化方法_oracle数据库优化方法

欢迎 发表评论:

文章目录
    搜索