数据库版本:Oracle12C
硬件类型:虚拟机
硬件配置:CPU 12 core,内存24GB,硬盘1000G
问题描述:类似一个准实时监控系统,前台展现巨慢无比,部分页面半小时无法刷出结果。
问题分析:已经大概知道该项目在性能优化这方面基本毫无准备,之前提到的一些解决方案完全未得到落实,对于索引只停留在可以加速概念上,对于索引的类型、结构、数据分布情况没有任何概念。登到监控平台看了一下,虚拟机的CPU使用率20%左右,内存使用率也是20%左右,和DBA同事探讨了一下大叶内存,认为在虚拟机上操作,会有一定风险。
问题步骤:
1、既然页面展示非常缓慢,照常规还是先分析一下执行最慢的SQL语句吧
代码语言:javascript复制SELECT *
FROM (
SELECT sa.sql_text,
sa.sql_fulltext,
sa.executions "执行次数",
round(sa.elapsed_time / 1000000, 2) "总执行时间",
round(sa.elapsed_time / 1000000 / sa.executions, 2) "平均执行时间",
sa.command_type,
sa.parsing_user_id "用户ID",
u.username "用户名",
sa.hash_value
FROM V$SQLAREA sa
LEFT JOIN ALL_USERS u
ON sa.parsing_user_id = u.user_id
WHERE sa.executions > 0
ORDER BY (sa.elapsed_time / sa.executions) DESC)
WHERE rownum <= 50;
最后输出50条语句,10条以上执行时间大于1小时,最长的几条两个半小时;50条执行均大于10分钟,当然这些语句未必是界面使用到的SQL语句,但显然解决这些问题,有助于减少系统资源争用。
2、总体上执行计划可看可不看,因为基本上没什么设计,一定是全表扫描,可为什么执行时间这么久,一般与表大小有很大关系,语句很简单,如下:
代码语言:javascript复制SELECT * FROM tablea
WHERE begintime>='2020-10-10 00:00:00' and begintime<='2020-10-10 23:59:59'
AND status='11'
3、还是先查一下DBA_SEGMENTS表吧,这个表内容挺多,但其实也不需要看那么多,大概看一下bytes和blocks即可,bytes是这个表的大小,blocks是这个表的块数,bytes越大代表数据量越大,bytes/blocks代表单位块里面的数据量,数据量越小代表该表经常被增删改查吧,简单除了一下该表约19个G。
代码语言:javascript复制DBA_SEGMENTS下个字段的含义
segment_type:段的类型,可能是table,index,logindex,lobsegment等。
header_file:表示这个段的头在哪个数据文件里,因为段可以跨数据文件。
header_block:表示这个段的头在数据文件的第几个block里。
bytes:段的大小(目前占用的大小?)
blocks:段占用了多少个block
extents:分配了多少个extent。
initial_extent:初始分配的extent大小(以byte计)。
next_extent:下一个分配的extent大小(以byte计)。如果为空表示是自动分配。(每个extent可以有不同大小,如果设置为uniform的话,每个extent就一样大小了)
min_extents:最少分配多少个extent(以个数计)。
max_extents:最多分配多少个extent(以个数计)。
pct_increase:percent increase表示第三个或后续的extent的大小比前一个增加的百分比,如第一个extent是64K,第二个是64K,pct_increase=50%,则第三个extent是64K*1.5=96K,第四个96K*1.5=144K,依次类推。
freelists:这个字段在字典管理的表空间中才有意义。
fresslist_groups:这个字段在字典管理的表空间中才有意义。
relative_fno:这个段所在数据文件的relative fno
buffer_pool:这个段的数据将被读取到哪一个buffer pool里
4、My GOD,一个虚拟机上竟然存在这么大的表,还是查看一下表结构,该表上就是普通的一个表,没有分区,首先分区是第一位的,还是需要吧。
5、再继续分析一下DBA_INDEXES吧,这里面东西更多,但可关注的其实不多,基本就看了两项leaf_blocks:索引中叶子块的数量、distinct_keys:不同索引值的数量。
代码语言:javascript复制owner: 索引拥有者
index_name:索引名字
index_type:索引类型
table_owner:表的拥有者
table_name:表名
table_type:表类型
uniqueness:是否唯一
compression:是否压缩
prefix_length:压缩键上前缀的列数量
tablespace_name:属于哪个表空间
ini_trans:事务表的初始大小由对象的ini_trans设置指定,默认2
max_trans:最大的max_trans条目,默认255
initial_extent:初始化区大小65536
next_extent:第二个区大小1048576
min_extents:段中允许的最小区大小
max_extents:段中允许的最大区大小,默认2g
pct_increase:后面区是前面区的增长百分比
pct_threshold:每个块中允许索引入口的百分比阀值
include_column:索引组织表主键索引中包含最后一列的列id
freelists:分配到这个段的进程自由列表数量
freelist_groups:分配到这个段的进程自由列表组的数量
pct_free:一个块中最小自由空间的百分比
logging:索引改变是否记录到日志
blevel:b树索引等级(从根块到叶子块的深度)
leaf_blocks:索引中叶子块的数量
distinct_keys:不同索引值的数量
avg_leaf_blocks_per_key:索引中的每个值平均在多少个叶子块中,如果是唯一或者主键,那么值恒等于1
avg_data_blocks_per_key:通过索引中的一个值指向表中的数据块,该数据块数量的平均值
clustering_factor:聚集因子,表示表中行基于索引排序程度
status:表示一个未分区的索引是合法的还是不可用的
sample_size:分析索引的参样大小
last_analyzed:最近分析索引统计信息的日期
degree:每个实例扫描索引的线程数
instances:索引被多少实例扫描
partitioned:索引是否分区
temporary:索引是否在临时表中
generated:索引名字是否是系统产生
secondary:索引是否通过odcindexcreate方法创建
buffer_pool:用于索引块的缓冲池
flash_cache:数据库 smart flash cache 的 hint用于索引块
cell_flash_cache:cell_flash_cache的hint用于索引块
user_stats:静态统计是否直接被用户使用
duration:临时表空间的持续时间
pct_direct_access:对于索引组织表上的secondary index ,行百分比的合理猜测
ityp_owner:对于域索引,索引类型的拥有者
ityp_name:对于域索引,索引类型名字
parameters:对于域索引,参数字符串
global_stats:索引的统计是否收集齐了
domidx_status:域索引的状态
domidx_opstatus:域索引的操作状态
funcidx_status:基于函数索引的状态
join_index:索引是否是结合的
iot_redundant_pkey_elim:在索引组织表中,冗余的主键列是否从从索引中删除
dropped:索引是否已经被删除,并在recycle中
visibility:索引是否可见
domidx_management如果是域索引,主索引是系统管理还是用户管理
segment_created:索引段是否已经创建
6、分析了一下DBA_INDEXES返回的结果,有三个索引,其中不同索引值的数量分别为2、6、50000 ,最后一个索引看起来还可以,可与总记录数比起来就不够看了,也就是说这几个索引,其实不仅没什么用,反过来还影响数据插入的效率。
7、刚好又看到了其他SQL语句,发现有SQL语句在使用XXX_ID做单一查询,本来想对表数据做个大概统计,无奈运行了10几分钟,还是跑不出结果。只能暂时认为该字段适合做索引了。
8、又陆陆续续分析其他SQL语句,还发现了一条AAA_ID=CHAR(BBB_ID)的语句。
初步花了半个小时了做了一下分析,总的来说,有些无语,基本的数据库性能优化概念是匮乏的,当然实施起来,要考虑业务连续性、要考虑尽可能减少代码修改,可能还会涉及一些其他性能资料收集和分析,但影响数据库性能90%都是由SQL导致的,SQL可能也不是最重要的,重要的是表的数据量、记录级和业务场景(增删改查)。
很久没玩这个了,简单分享一下。