背景
在当今的软件开发领域,尽管主流开发模式往往倾向于采用单表模式,力图尽可能地减少表之间的连接操作,以期达到提高数据处理效率、简化应用逻辑等目的。然而,对于那些已经上线运行多年的运维老系统而言,它们内部往往遗留了大量的复杂 SQL 语句。这些 SQL 语句在系统初建时,可能是基于当时的业务需求和数据量规模设计与实现。但随着时间的推移,数据库中的数据量持续不断地累积和膨胀,原先执行起来速度较快的 SQL 语句,在面对如今海量的数据时,往往会出现性能大幅下降的情况,甚至可能成为整个系统的性能瓶颈,严重影响业务的正常运转。
因此,在这样的背景下,对这些关键 SQL 语句优化变得重要,而优化的前提则是对SQL进行分析,其重要手段就是查看SQL语句的执行计划。
本文以Oracle数据库为例,介绍下如何通过执行计划来分析和解决问题。
一、什么是执行计划?
执行计划是 Oracle 数据库用于执行 SQL 语句的一系列步骤。它描述了数据库如何访问和处理数据,包括表的扫描方式、连接顺序、使用的索引等。
需要注意的是,数据库根据内部的优化器成本模型来生成最优的执行计划,以期以最快速度、最少资源完成 SQL 语句的执行。因此,并不是添加了索引,实际执行的时候一定会使用索引,数据库会进行判断和处理。
二、如何查看执行计划?
查看执行计划有以下几种方式:
V$SQL_PLAN 视图
首先,通过系统视图V$SQL
获取到SQL_ID,
SELECT * FROM V$SQL order by last_load_time desc
如下图所示:
然后,通过V$SQL_PLAN
动态性能视图,查看对应的 SQL 语句的执行计划。
SELECT * FROM V$SQL_PLAN WHERE SQL_ID = '62v30b9v1fvcc';
结果如下图所示:
这种方式依托于oracle数据库提供的视图,操作起来比较繁琐,且结果也不够直观,不推荐。
explain plan 语句
语法
EXPLAIN PLAN FOR
是最基本的查看执行计划的语法。它将生成的执行计划存储在数据字典表中。
分为两步,第一步我们需要生成执行计划,可以使用以下语句创建:
EXPLAIN PLAN SET STATEMENT_ID = 'stmt1' FOR select * from WEB_LINK where name='Property Sheet Pages';
这条语句会为查询 WEB_LINK 表中 name 为 Property Sheet Pages 的记录生成执行计划,并且将这条计划标记为 ‘stmt1’。
第二步是查看执行计划,通过查询 PLAN_TABLE
表来查看具体的执行计划。
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE', 'stmt1', 'ALL'));
这里 DBMS_XPLAN.DISPLAY
函数用于格式化和显示存储在 PLAN_TABLE
中的执行计划,参数 ‘PLAN_TABLE’ 指明存储计划的表,‘stmt1’ 是之前指定的标记,‘ALL’ 表示显示所有信息,包括基本节点信息、成本、分区信息等。
执行结果如下:
Plan hash value: 506061415--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 165 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| WEB_LINK | 1 | 165 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | WEB_LINK_N | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------1 - SEL$1 / WEB_LINK@SEL$12 - SEL$1 / WEB_LINK@SEL$1Predicate Information (identified by operation id):
---------------------------------------------------2 - access("NAME"='Property Sheet Pages')Column Projection Information (identified by operation id):
-----------------------------------------------------------1 - "WEB_LINK"."IDENTITY"[VARCHAR2,20], "WEB_LINK"."DESCRIPTION"[VARCHAR2,255], "WEB_LINK"."GROUP_ID"[VARCHAR2,30], "WEB_LINK"."MODIFIABLE"[VARCHAR2,1], "WEB_LINK"."MODIFIED_ON"[DATE,7], "WEB_LINK"."MODIFIED_BY"[VARCHAR2,30], "WEB_LINK"."REMOVEFLAG"[VARCHAR2,1], "NAME"[VARCHAR2,100], "WEB_LINK"."URL"[VARCHAR2,255], "WEB_LINK"."SEPARATE_WINDOW"[VARCHAR2,1]2 - "WEB_LINK".ROWID[ROWID,10], "NAME"[VARCHAR2,100]
这种方式相比第一种,无论是便捷性,还是直观性都要好上不少。
自动执行计划
在 SQL*Plus 中,可以通过设置 AUTOTRACE
打开自动追溯功能后,来自动显示执行计划,包括操作步骤、行数预估、字节预估和成本等信息。
在 SQL Developer 中,执行 SQL 语句后,可以在 “执行计划” 选项卡中查看图形化或详细文本形式的执行计划,非常直观方便。
该方式的便捷性和直观性最佳,推荐采用该方式来查看执行计划。