Oracle开发者性能课第3课(我的查询做了多少工作)实验
Posted dingdingfish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle开发者性能课第3课(我的查询做了多少工作)实验相关的知识,希望对你有一定的参考价值。
概述
本实验参考DevGym中的实验指南。
创建环境
首先创建表:
-- 此参数默认值即为auto
alter session set WORKAREA_SIZE_POLICY = auto;
create table colours as
select 'red' colour from dual
union all
select 'blue' colour from dual
union all
select 'green' colour from dual
union all
select 'orange' colour from dual
union all
select 'yellow' colour from dual
union all
select 'purple' colour from dual
union all
select 'brown' colour from dual
union all
select 'white' colour from dual
union all
select 'black' colour from dual;
create table bricks as
select rownum brick_id, colour, sysdate insert_datetime, lpad ( 'x', 100, 'x' ) stuff
from colours
cross join (
select * from dual
connect by level <= 250
);
create table pens as
select rownum pen_id, colour, sysdate insert_datetime, lpad ( 'x', 100, 'x' ) stuff
from colours
cross join (
select * from dual
connect by level <= 250
);
create table bricks_indexed as
select * from bricks;
create index brick_colour_i on bricks_indexed ( colour );
alter table bricks_indexed
modify colour not null;
create or replace view complex_query as
select count ( row_id ) row_count from (
select rownum row_id, bricks.*, pens.*
from colours
join pens
on colours.colour = pens.colour
join bricks
on colours.colour = bricks.colour
order by bricks.brick_id
);
-- 结果为562500行
select /* init */* from complex_query;
-- 结果为2250行
select /* init */count ( colour ) from bricks_indexed;
查看数据:
SQL> select * from colours;
COLOUR
_________
red
blue
green
orange
yellow
purple
brown
white
black
9 rows selected.
-- bricks 的行数为colours的行数乘以250
-- lpad ( 'x', 100, 'x' ) 表示在x的左侧填充x,直到宽度为100
SQL> select count(*) from colours;
COUNT(*)
___________
9
SQL> select count(*) from bricks;
COUNT(*)
___________
2250
tu
SQL> select * from bricks where rownum <= 2;
BRICK_ID COLOUR INSERT_DATETIME STUFF
___________ _________ __________________ _______________________________________________________________________________________________________
1 red 29-OCT-21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2 blue 29-OCT-21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-- pens和bricks的生成方法类似,因此行数一样,结构类似
SQL> select count(*) from pens;
COUNT(*)
___________
2250
-- bricks_indexed结构和数据与bricks完全一样,只是多了索引
SQL> select count(*) from bricks_indexed;
COUNT(*)
___________
2250
-- complex_query只有1行
SQL> select * from complex_query;
ROW_COUNT
____________
562500
衡量完成的工作
为了使 SQL 语句更快,您需要减少它们所做的工作量。 两个关键资源是 CPU 和 I/O。
I/O 通常是数据库中的限制因素。 在所有其他条件相同的情况下,一个语句执行的 I/O 越少,它的扩展性就越好。
Oracle 数据库以块的形式存储行。 要访问一行,它必须首先读取该行所在的块。每次数据库读取一个新块,这产生另一个逻辑 I/O 操作。
因此,在 Oracle 数据库中衡量的关键指标之一是查询的逻辑 I/O。 这有两个组成部分:
- Consistent (read) gets
- Current mode gets
无论是哪种模式,当读取一个块时,如果它没有缓存在内存中,数据库就会进行物理读取。 这将从磁盘中获取块。
在下例的执行计划中,Buffers表示Consistent gets 和 Current mode gets的和:
select /*+ gather_plan_statistics */count(*) from bricks;
select *
from table(dbms_xplan.display_cursor(format => 'iosTATS LAST'));
PLAN_TABLE_OUTPUT
__________________________________________________________________________________________
SQL_ID b5x61q1pa25jj, child number 0
-------------------------------------
select /*+ gather_plan_statistics */count(*) from bricks
Plan hash value: 1774413877
---------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 41 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 41 |
| 2 | TABLE ACCESS FULL| BRICKS | 1 | 2250 | 2250 |00:00:00.01 | 41 |
---------------------------------------------------------------------------------------
14 rows selected.
Consistent get
访问的块在过去的某个时间点存在。 这通常是查询开始时的时间。 这确保查询仅返回查询开始时存在的值。 在此之后所做的任何更改都将被忽略。
在运行查询或处理 UPDATE 和 DELETE 的 where 子句时,您将看到这些Consistent get。
Current mode get
这将获取当前存在的块。 在 INSERT、UPDATE 和 DELETE 语句中更改数据时,您将看到Current mode get。
单个操作执行了多少个逻辑 I/O?
format 中的IOSTATS可以得到I/O信息,但此信息是累计的,因此需要减去其直接子节点的值。
在下例中,虽然步骤2 HASH JOIN
的Buffers显示为43,但减去其下直属的2个子节点后等于0,因此可认为没有I/O。但其并非没做工作,哈希是在内存中进行,而内存足够,因此没有借助磁盘。整个执行计划中,I/O最多的操作为BRICKS表的全表扫描(41)。
select /*+ gather_plan_statistics */
count (*)
from colours c
join bricks b
on c.colour = b.colour;
select *
from table(dbms_xplan.display_cursor(:LIVESQL_LAST_SQL_ID, format => 'IOSTATS LAST'));
PLAN_TABLE_OUTPUT
____________________________________________________________________________________________
SQL_ID 15r45fvzv9kgm, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count (*) from colours c
join bricks b on c.colour = b.colour
Plan hash value: 1769408843
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 43 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 43 |
|* 2 | HASH JOIN | | 1 | 2250 | 2250 |00:00:00.01 | 43 |
| 3 | TABLE ACCESS FULL| COLOURS | 1 | 9 | 9 |00:00:00.01 | 2 |
| 4 | TABLE ACCESS FULL| BRICKS | 1 | 2250 | 2250 |00:00:00.01 | 41 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("C"."COLOUR"="B"."COLOUR")
22 rows selected.
单个操作使用了多少内存?
format 中的MEMSTATS可显示内存统计信息。
例如:
select /*+ gather_plan_statistics */* from complex_query;
select *
from table(dbms_xplan.display_cursor( format => 'MEMSTATS LAST'));
PLAN_TABLE_OUTPUT
________________________________________________________________________________________________________________________
SQL_ID 85b35ny7rud7t, child number 0
-------------------------------------
select /*+ gather_plan_statistics */* from complex_query
Plan hash value: 1782653251
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.11 | | | |
| 1 | VIEW | COMPLEX_QUERY | 1 | 1 | 1 |00:00:00.11 | | | |
| 2 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.11 | | | |
| 3 | VIEW | | 1 | 562K| 562K|00:00:00.11 | | | |
| 4 | SORT ORDER BY | | 1 | 562K| 562K|00:00:00.11 | 17M| 1546K| 15M (0)|
| 5 | COUNT | | 1 | | 562K|00:00:00.02 | | | |
|* 6 | HASH JOIN | | 1 | 562K| 562K|00:00:00.01 | 1856K| 1856K| 1075K (0)|
| 7 | TABLE ACCESS FULL | BRICKS | 1 | 2250 | 2250 |00:00:00.01 | | | |
|* 8 | HASH JOIN | | 1 | 2250 | 2250 |00:00:00.01 | 2171K| 2171K| 1089K (0)|
| 9 | TABLE ACCESS FULL| COLOURS | 1 | 9 | 9 |00:00:00.01 | | | |
| 10 | TABLE ACCESS FULL| PENS | 1 | 2250 | 2250 |00:00:00.01 | | | |
---------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("COLOURS"."COLOUR"="BRICKS"."COLOUR")
8 - access("COLOURS"."COLOUR"="PENS"."COLOUR")
28 rows selected.
和I/O不同,内存不是累计的。其中Used-Mem为实际使用。OMem 和1Mem是估值。
按照这里的解释:
- OMem 是仅在内存中执行操作所需的内存估计。 您可以将其视为最佳(Optimal)执行。
- 1Mem 是在单次传递中执行操作所需的内存估计(从磁盘或临时磁盘读/写)。 称为一次性执行(即 1Mem)
单个操作进行了多少次磁盘读写?
当数据库没有足够内存对行进行排序时,它会将它们写入临时磁盘。 您可以在使用 MEMSTATS 格式的 Used-Tmp 列中查看所需的磁盘容量。
使用下面的SQL进行测试:
select /*+ gather_plan_statistics */ row_count from complex_query;
select *
from table(dbms_xplan.display_cursor( format => 'ALLSTATS LAST'));
正常时的执行计划:
PLAN_TABLE_OUTPUT
__________________________________________________________________________________________________________________________________
SQL_ID 1tatyc2s9n297, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ row_count from complex_query
Plan hash value: 1782653251
-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.10 | 87 | | | |
| 1 | VIEW | COMPLEX_QUERY | 1 | 1 | 1 |00:00:00.10 | 87 | | | |
| 2 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.10 | 87 | | | |
| 3 | VIEW | | 1 | 562K| 562K|00:00:00.10 | 87 | | | |
| 4 | SORT ORDER BY | | 1 | 562K| 562K|00:00:00.10 | 87 | 17M| 1546K| 15M (0)|
| 5 | COUNT | | 1 | | 562K|00:00:00.02 | 87 | | | |
|* 6 | HASH JOIN | | 1 | 562K| 562K|00:00:00.02 | 87 | 1856K| 1856K| 1070K (0)|
| 7 | TABLE ACCESS FULL | BRICKS | 1 | 2250 | 2250 |00:00:00.01 | 42 | | | |
|* 8 | HASH JOIN | | 1 | 2250 | 2250 |00:00:00.01 | 45 | 2171K| 2171K| 1071K (0)|
| 9 | TABLE ACCESS FULL| COLOURS | 1 | 9 | 9 |00:00:00.01 | 3 | | | |
| 10 | TABLE ACCESS FULL| PENS | 1 | 2250 | 2250 |00:00:00.01 | 42 | | | |
-------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("COLOURS"."COLOUR"="BRICKS"."COLOUR")
8 - access("COLOURS"."COLOUR"="PENS"."COLOUR")
28 rows selected.
通过设定workarea_size_policy 和sort_area_size(单位为字节)模拟内存不够:
SQL> show parameter sort_area_size ;
NAME TYPE VALUE
-------------- ------- -----
sort_area_size integer 65536
SQL> show parameter workarea_size_policy;
NAME TYPE VALUE
-------------------- ------ -----
workarea_size_policy string AUTO
alter session set workarea_size_policy = manual;
alter session set sort_area_size = 25000;
此时的执行计划,可以看到多了Used-Tmp列:
TABLE_OUTPUT
______________________________________________________________________________________________________________________________________________________________
SQL_ID 1tatyc2s9n297, child number 1
-------------------------------------
select /*+ gather_plan_statistics */ row_count from complex_query
Plan hash value: 1782653251
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.84 | 111 | 2573 | 2558 | | | | |
| 1 | VIEW | COMPLEX_QUERY | 1 | 1 | 1 |00:00:00.84 | 111 | 2573 | 2558 | | | | |
| 2 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.84 | 111 | 2573 | 2558 | | | | |
| 3 | VIEW | | 1 | 562K| Oracle开发者性能课第6课(如何创建物化视图)实验