小伙伴们,有没有经常和开发一起定位sql查询和分析性能问题,经常拿到一串sql进行先做个EXPLAIN,EXPLAIN PLAN作为Oracle数据库提供的一种用于分析SQL语句执行计划的工具,运行后,其实不会真的执行SQL语句而是通过模拟优化器生成执行计划,同时生成的执行计划被写入一个特定的表(默认为PLAN_TABLE,如果没有,实需使用utlxpan的sql新建,实操中有脚本)
第三方DATAGRIP,PL/SQL,Navicat等各种工具,一键EXPLAIN PLAN,同样查询PLAN_TABLE表来了解SQL语句的执行路径,Oracle执行了哪些,信息保存在哪里,API调用是否可行。
字段名 |
说明 |
调优意义 |
OPERATION |
操作类型(TABLE ACCESS, INDEX SCAN等) |
识别全表扫描等性能瓶颈 |
OPTIONS |
操作选项(FULL, RANGE SCAN等) |
判断索引使用情况 |
CARDINALITY |
优化器估算行数 |
与实际行数偏差>10%需警惕 |
COST |
相对执行成本 |
成本突增预示性能问题 |
ACCESS_PREDICATES |
访问谓词 |
验证索引使用条件 |
FILTER_PREDICATES |
过滤谓词 |
识别数据过滤效率 |
SYS@CDB$ROOT> @?/rdbms/admin/utlxplan.sql
SYS@CDB$ROOT> DESC PLAN_TABLE;
Name Null? Type
____________________ ________ _________________
STATEMENT_ID VARCHAR2(30)
PLAN_ID NUMBER
TIMESTAMP DATE
REMARKS VARCHAR2(4000)
OPERATION VARCHAR2(30)
OPTIONS VARCHAR2(255)
OBJECT_NODE VARCHAR2(128)
OBJECT_OWNER VARCHAR2(128)
OBJECT_NAME VARCHAR2(128)
OBJECT_ALIAS VARCHAR2(261)
OBJECT_INSTANCE NUMBER(38)
OBJECT_TYPE VARCHAR2(30)
OPTIMIZER VARCHAR2(255)
SEARCH_COLUMNS NUMBER
ID NUMBER(38)
PARENT_ID NUMBER(38)
DEPTH NUMBER(38)
POSITION NUMBER(38)
COST NUMBER(38)
CARDINALITY NUMBER(38)
……………………
EXPLAIN PLAN
[ SET STATEMENT_ID = 'statement_id' ]
[ INTO [schema.]table_name ]
FOR sql_statement;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- 创建测试表HR.T4EXPLAIN,直接拷贝了DBA_OBJECTS的数据
CREATE TABLE HR.T4EXPLAIN AS SELECT * FROM dba_objects;
--Table HR.T4EXPLAIN created.
-- 生成执行计划
EXPLAIN PLAN FOR
SELECT object_id, object_name, object_type
FROM HR.T4EXPLAIN
WHERE object_type = 'TABLE';
--Explained.
-- 基本格式
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--SYS@CDB$ROOT> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Plan hash value: 2206274169
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1537 | 81461 | 446 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T4EXPLAIN | 1537 | 81461 | 446 (1)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_TYPE"='TABLE')
13 rows selected.
-- 更加详细的格式
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
SYS@CDB$ROOT> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
Plan hash value: 2206274169
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1537 | 81461 | 446 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T4EXPLAIN | 1537 | 81461 | 446 (1)| 00:00:01 |
-------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / "T4EXPLAIN"@"SEL$1"
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_TYPE"='TABLE')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22],
"OBJECT_TYPE"[VARCHAR2,23]
24 rows selected.
SYS@CDB$ROOT>
-- 查看当前会话的执行计划在PLAN_TABLE$中的记录
SELECT operation, options, object_name, id, cardinality, cost
FROM sys.plan_table;
-- 创建测试表(支持AI特性)
CREATE TABLE ai_sales_data (
sale_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
product_id NUMBER,
sale_date DATE,
quantity NUMBER,
amount NUMBER(10,2),
ai_features VECTOR
);
--Table AI_SALES_DATA created.
--插入语句
INSERT INTO ai_sales_data (product_id, sale_date, quantity, amount, ai_features)
SELECT
ROWNUM,
SYSDATE - DBMS_RANDOM.VALUE(1,365),
ROUND(DBMS_RANDOM.VALUE(1,100)),
DBMS_RANDOM.VALUE(10,1000),
VECTOR('['
|| DBMS_RANDOM.VALUE() || ','
|| DBMS_RANDOM.VALUE() || ','
|| DBMS_RANDOM.VALUE() || ']'
)
FROM dual
CONNECT BY LEVEL <= 1000;
COMMIT;
-- 确保统计信息最新
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'AI_SALES_DATA');
-- 生成向量搜索执行计划
EXPLAIN PLAN FOR
SELECT /*+ VECTOR_INDEX(sales_vec_idx) */
sale_id,
amount,
VECTOR_DISTANCE(ai_features, VECTOR('[0.5, 0.3, 0.8]'), EUCLIDEAN) AS dist
FROM ai_sales_data
WHERE VECTOR_DISTANCE(ai_features, VECTOR('[0.5, 0.3, 0.8]'), EUCLIDEAN) < 0.2
ORDER BY dist;
--Explained.
--查看完整计划详细信息
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(
format => 'ALL'
));
--
SYS@CDB$ROOT> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Plan hash value: 1060895572
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 39 | 585 | 8 (13)| 00:00:01 |
| 1 | SORT ORDER BY | | 39 | 585 | 8 (13)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| AI_SALES_DATA | 39 | 585 | 7 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(VECTOR_DISTANCE("AI_FEATURES" /*+ LOB_BY_VALUE */ ,
VECTOR('[0.5, 0.3, 0.8]', *, *, * /*+ USEBLOBPCW_QVCGMD */ ),
EUCLIDEAN)<2.0000000000000001E-001D)
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO (SYSTEM))
20 rows selected.
SYS@CDB$ROOT>
--Oracle 23ai不要直接在 DBMS_XPLAN.DISPLAY 中组合 ADAPTIVE +VECTOR +AI,推荐的格式组合或分多次查询获取不同方面的信息。
-- 1. 直接查询PLAN_TABLE(基本计划信息)
SELECT
id,
LPAD(' ', depth*2) || operation || ' ' || options AS operation,
object_name,
cardinality AS "ROWS",
cost
FROM plan_table
ORDER BY id;
-- 方法2: 使用 DISPLAY 函数获取 JSON
-- 获取最新执行计划
SELECT DBMS_XPLAN.DISPLAY(
format => 'JSON'
) AS json_plan
FROM plan_table
WHERE id = 0;
--JSON格式
SELECT DBMS_XPLAN.DISPLAY(statement_id => NULL, format => 'JSON') AS json_plan
FROM DUAL;
oracle.sql.ARRAY@2b7774d5
oracle.sql.ARRAY@44bbb7c6
oracle.sql.ARRAY@3303e89e
--