性能诊断用于了解操作系统以及数据库的各项性能指标是否达到要求,以满足系统正常运行需要。通过性能诊断,可以更好地了解系统资源的使用情况、以及数据库的状态,提前避免由于性能不足引发的各种问题。性能诊断在数据库运维中具有极大的实用价值。
硬件信息收集:
硬件 | 硬件配置命令 | 运行情况监控命令 |
---|---|---|
CPU | cat /proc/cpuinfo |
top vmstat sar |
内存 | cat /proc/meminfo |
top vmstat free |
磁盘 | RAID配置信息 | iostat |
网络 | ifconfig |
ping route netstat |
分类 | 说明/命令示例 |
---|---|
数据库版本 | SELECT * FROM V$VERSION; |
数据库架构 | 单机/主备/读写分离/DSC |
交易类型 | OLTP/OLAP/混合型 |
配置参数 | 资源类参数/查询优化参数 |
数据库规模 | 库大小/大表/分区表/索引 |
关注的对象 | 触发器/大字段/物化视图/外部链接 |
会话数 | SELECT COUNT(*) FROM V$SESSIONS; |
事务数 | SELECT COUNT(*) FROM V$TRX; |
等待事件 | SELECT * FROM V$TRXWAIT; |
内存池 | SELECT * FROM V$MEM_POOL; |
热点 | 热点表/热点SQL |
分类 | 需关注内容 |
---|---|
硬件 | 硬件更换/重启/升级记录 |
软件 | 新业务上线/新模块适配情况 |
用户 | 业务用户增长/访问时间调整/访问模块集中度 |
[root@dj01 ~]# vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 941532 2292 375188 0 0 153 8 117 155 0 1 98 1 0
0 0 0 940968 2292 375220 0 0 0 0 206 197 0 0 99 1 0
0 0 0 941012 2292 375220 0 0 0 0 202 191 0 1 99 0 0
0 0 0 941052 2292 375220 0 0 0 0 197 192 0 0 96 3 0
0 0 0 941012 2292 375220 0 0 0 0 192 192 0 0 100 0 0
指标解读如下:
r:如果在 procs 中运行的序列 (processr) 是连续的大于在系统中的 CPU 的个数,表示 CPU 比较忙,系统现在运行比较慢,有多数的进程等待 CPU。如果 r 的输出数大于系统中可用 CPU 个数的 4 倍,则系统面临着 CPU 短缺的问题,或者是 CPU 的速率过低,系统中有多数的进程在等待 CPU,造成系统中进程运行过慢。
b:在 procs 中运行的序列 (processb),即处于不可中断状态的进程数,如果连续为 CPU 的 2~3 倍,就表明 CPU 排队比较严重。
如果 r 连续大于 CPU 的个数,甚至是 CPU 个数的几倍;b 也持续有值,甚至是 CPU 的 2~3 倍,并且 id 也持续小于 50%,wa 也比较小,这就表明 CPU 负荷很严重。
in:每秒产生的中断次数。
cs:每秒产生的上下文切换次数。
in 和 cs 这两个值越大,由内核消耗的 CPU 时间会越大。
us:用户进程消耗的 CPU 时间百分比。us 的值比较高时,说明用户进程消耗的 CPU 时间多,在服务高峰期持续大于 50~60,是可以接受的范围,但是如果长期超过 50% ,就需要考虑优化程序算法。
sy:内核进程消耗的 CPU 时间百分比。sy 的值比较高时,说明系统内核消耗的 CPU 资源多,对于这种非良性表现需要检查原因。
wa:IO 等待消耗的 CPU 时间百分比。wa 的值比较高时,说明 IO 等待比较严重,可能是由于磁盘大量做随机访问造成的,也有可能是磁盘出现了瓶颈(块操作)。
id:CPU 处于空闲状态时间百分比,如果空闲时间 (cpu id) 持续为 0 并且系统时间 (cpu sy) 是用户时间的两倍 (cpu us) ,系统则面临着 CPU 资源的短缺,如果在服务高峰期持续小于 50,是可以接受的范围。
除此之外,还可以用以下方法分析 CPU 性能:
观察 CPU 的使用率和 CPU 运行进程队列长度及负载,可以使用命令:sar -u 1 5、sar -q 1 5。
查看具体是什么进程在消耗 CPU,可以使用命令:top、ps -auxw|more。
知道了某个进程消耗大量的 CPU,想了解该进程详细内容,可以使用命令:strace。
[root@dj01 ~]# top
top - 18:05:38 up 19 min, 2 users, load average: 0.00, 0.01, 0.03
Tasks: 108 total, 2 running, 105 sleeping, 1 stopped, 0 zombie
%Cpu(s): 3.0 us, 6.1 sy, 0.0 ni, 90.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1865308 total, 940416 free, 547132 used, 377760 buff/cache
KiB Swap: 4194300 total, 4194300 free, 0 used. 1129100 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 193448 6460 4080 S 0.0 0.3 0:01.09 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.00 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
6 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/u256:0
sar -u 1 5 # CPU使用率统计
[root@dj01 ~]# sar -u 1 5
Linux 3.10.0-862.el7.x86_64 (dj01) 08/01/2025 _x86_64_ (2 CPU)
06:09:37 PM CPU %user %nice %system %iowait %steal %idle
06:09:38 PM all 0.00 0.00 1.52 0.00 0.00 98.48
06:09:39 PM all 0.50 0.00 0.00 4.48 0.00 95.02
06:09:40 PM all 0.00 0.00 0.50 0.00 0.00 99.50
06:09:41 PM all 0.00 0.00 0.50 0.00 0.00 99.50
06:09:42 PM all 0.50 0.00 0.00 1.01 0.00 98.49
Average: all 0.20 0.00 0.50 1.10 0.00 98.19
us
> 60% → 用户进程消耗过高(需优化SQL/程序)sy
> 30% → 内核处理开销大(检查系统调用)id
< 30% + wa
> 40% → CPU过载或I/O阻塞iostat -x 1 5 # 查看I/O详情
[root@qltest ~]# iostat -d -x -k 1 5
Linux 4.19.90-52.15.v2207.ky10.x86_64 (qltest) 2025年07月26日 _x86_64_ (4 CPU)
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz aqu-sz %util
dm-0 0.21 0.87 0.00 0.00 0.75 4.14 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
dm-1 0.14 2.96 0.00 0.00 1.35 21.93 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
dm-2 0.14 2.96 0.00 0.00 1.35 21.93 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
dm-3 0.30 5.55 0.00 0.00 0.86 18.78 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
sda 21.67 1137.94 12.44 36.48 1.22 52.51 3.13 88.75 3.59 53.43 0.79 28.38 0.00 0.00 0.00 0.00 0.00 0.00 0.02 2.04
scd0 0.07 2.62 0.00 0.00 1.36 37.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
结果解读:
rrqm/s:每秒进行 merge(多个 IO 的合并)读操作的数量。
wrqm/s:每秒进行 merge(多个 IO 的合并)写操作的数量。
rsec/s:每秒读取的扇区数。
wsec/s:每秒写入的扇区数。
rKB/s:每秒读多少 k 字节,在 kernel 2.4 以上,rkB/s=2×rsec/s,因为一个扇区为 512 bytes。
wKB/s:每秒写多少 k 字节,在 kernel 2.4 以上,wkB/s=2×wsec/s,因为一个扇区为 512 bytes。
avgrq-sz:平均请求扇区的大小。
avgqu-sz:是平均请求队列的长度,队列长度越短越好。
await:每一个 IO 请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为 IO 的响应时间,一般地系统 IO 响应时间应该低于 5 ms,如果大于 10 ms 就比较大了。这个时间包括了队列时间和服务时间,一般情况下,await 大于 svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
svctm:表示平均每次设备 I/O 操作的服务时间(以毫秒为单位)。如果 svctm 的值与 await 很接近,表示几乎没有 I/O 等待,磁盘性能很好,如果 await 的值远高于 svctm 的值,则表示 I/O 队列等待太长,系统上运行的应用程序将变慢。
%util:在统计时间内所有处理 IO 时间,除以总共统计时间,该参数表示设备的繁忙程度,如果该参数是 100% 表示设备已经接近满负荷运行了(如果是多磁盘,即使 %util 是 100%,因为磁盘的并发能力,所以磁盘使用不一定到了瓶颈)。
iotop # 定位高I/O进程
Total DISK READ : 0.00 B/s | Total DISK WRITE : 0.00 B/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 15.69 K/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1409 be/4 root 0.00 B/s 0.00 B/s 0.00 % 3.71 % [kworker/1:1]
512 be/3 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % auditd
1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % systemd --switched-root --system --deserialize 22
2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd]
3 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/0]
5 be/0 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/0:0H]
6 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/u256:0]
7 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [migration/0]
8 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [rcu_bh]
9 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [rcu_sched]
10 be/0 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [lru-add-drain]
11 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [watchdog/0]
12 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [watchdog/1]
13 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [migration/1]
14 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/1]
15 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/1:0]
16 be/0 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/1:0H]
1041 be/4 dmdba 0.00 B/s 0.00 B/s 0.00 % 0.00 % dmserver path=/home/dmdba/dmdbms/data/DAMENG/dm.ini -noconsole [dm_tskwrk_thd]
结果解读:
DISK READ 和 DISK WRITE 字段:代表块设备在采样时间内的 I/O 带宽。
SWAPIN 和 IO 字段:表示当前进程或线程花费在页面换入和等待 I/O 的时间。
PRIO 字段:表示 I/O 优先级。
Total DISK READ 和 Total DISK WRITE 字段:表示总的 I/O 读写情况。
ethtool eth0
(查看Speed/Duplex)ping -c 4 目标IP
sar -n DEV 1 3
SELECT COUNT(*) FROM V$SESSIONS WHERE STATE='ACTIVE';
SELECT sess_id, sql_text, datediff(ss,last_recv_time,sysdate)
FROM V$SESSIONS WHERE STATE='ACTIVE' AND datediff(ss,last_recv_time,sysdate)>=2;
SELECT O.NAME,L.* FROM V$LOCK L,SYSOBJECTS O WHERE L.TABLE_ID=O.ID AND BLOCKED=1;
WITH LOCKS
AS (SELECT O.NAME,L.*,S.SESS_ID,S.SQL_TEXT,S.CLNT_IP,S.LAST_SEND_TIME
FROM V$LOCK L, SYSOBJECTS O, V$SESSIONS S
WHERE L.TABLE_ID = O.ID AND L.TRX_ID = S.TRX_ID),
LOCK_TR
AS (SELECT TRX_ID WT_TRXID, TID BLK_TRXID
FROM LOCKS
WHERE BLOCKED = 1),
RES
AS (SELECT SYSDATE STATTIME,T1.NAME,T1.SESS_ID WT_SESSID,S.WT_TRXID,
T2.SESS_ID BLK_SESSID,S.BLK_TRXID,T2.CLNT_IP,
SF_GET_SESSION_SQL (T1.SESS_ID) FULSQL,
DATEDIFF (SS, T1.LAST_SEND_TIME, SYSDATE) SS,
T1.SQL_TEXT WT_SQL
FROM LOCK_TR S, LOCKS T1, LOCKS T2
WHERE T1.LTYPE = 'OBJECT'
AND T1.TABLE_ID <> 0
AND T2.LTYPE = 'OBJECT'
AND T2.TABLE_ID <> 0
AND S.WT_TRXID = T1.TRX_ID
AND S.BLK_TRXID = T2.TRX_ID)
SELECT DISTINCT WT_SQL,CLNT_IP,SS,WT_TRXID,BLK_TRXID
FROM RES;
跟踪日志文件是一个纯文本文件,以 ‘dmsql_实例名_日期_时间命名’,默认生成在 DM 安装目录的 log 子目录下。跟踪日志内容包含系统各会话执行的 SQL 语句、参数信息、错误信息、执行时间等。跟踪日志主要用于分析错误和分析性能问题,基于跟踪日志可以对系统运行状态进行分析。跟踪日志配置方式如下:
1.配置 dm.ini 文件,设置 SVR_LOG = 1 以启用 sqllog.ini 配置,该参数为动态参数,可通过调用数据库函数直接修改。
SP_SET_PARA_VALUE(1,'SVR_LOG',1);
2.配置数据文件目录下的 sqllog.ini 文件。
[dmdba@localhost DAMENG]$ cat sqllog.ini
BUF_TOTAL_SIZE = 10240 #SQLs Log Buffer Total Size(K)(1024~1024000)
BUF_SIZE = 1024 #SQLs Log Buffer Size(K)(50~409600)
BUF_KEEP_CNT = 6 #SQLs Log buffer keeped count(1~100)
[SLOG_ALL]
FILE_PATH = ../log
PART_STOR = 0
SWITCH_MODE = 1
SWITCH_LIMIT = 100000
ASYNC_FLUSH = 0
FILE_NUM = 200
ITEMS = 0
SQL_TRACE_MASK = 2:3:23:24:25
MIN_EXEC_TIME = 0
USER_MODE = 0
USERS =
3.如果对 sqllog.ini 进行了修改,可通过调用以下函数即时生效,无需重启数据库。
SP_REFRESH_SVR_LOG_CONFIG();
4.sqllog.ini 文件配置成功后可在 dmsql 指定目录下生成 dmsql 开头的 log 日志文件。日志内容如下所示:
jdbc:dm://IP:PORT?logLevel=all&logDir=/logs&statEnable=true
logLevel
:设置日志级别(error/warn/sql)statSlowSqlCount
:统计慢SQL TopN属性 | 说明 | 是否必须设置 |
---|---|---|
logDir | 日志等其他一些 JDBC 过程文件生成目录,默认为 jvm 当前工作目录; | 否 |
logLevel | 生成日志的级别,日志按从低到高依次如下(off: 不记录;error: 只记录错误日志;warn: 记录警告信息;sql: 记录 sql 执行信息;info: 记录全部执行信息;all: 记录全部),高级别同时记录低级别的信息;默认 off; | 否 |
logFlushFreq | 日志刷盘频率;单位 s,有效值范围 0~2147483647;默认 60; | 否 |
statEnable | 是否启用状态监控;取值 1/0 或 true/false;默认 false; | 否 |
statDir | 状态监控信息以文本文件形式输出的目录,默认为 jvm 当前工作目录; | 否 |
statFlushFreq | 状态监控统计信息写文件刷盘频率;单位 s,有效值范围 0~2147483647;0 表示不写文件;默认 10; | 否 |
statSlowSqlCount | 统计慢 sql top 行数;有效值范围 0~1000;默认 100; | 否 |
statHighFreqSqlCount | 统计高频 sql top 行数;有效值范围 0~1000;默认 100; | 否 |
数据库架构 | 架构介绍 | 架构特性 |
---|---|---|
数据守护集群DMDDataWatch | DMDDataWatch 是一种高可用数据库解决方案,主备节点间通过日志同步来保证数据的同步,可以实现数据库快速切换与灾难性恢复,满足用户对数据安全性和高可用性的需求,提供不间断的数据库服务。 | 实时保证数据完全一致,备库支持临时表,故障秒级切换。 |
读写分离集群DMRWC | DMRWC 在保障主库和备库事务强一致的前提下,开创性地在接口层(JDBC、DPI 等)将只读操作自动分流到备库,有效降低主库的负载,提升系统吞吐量,适用于读多写少的业务场景。 | 事务自动分发,OA 办公系统的最佳选择,高可用性。 |
数据共享集群DMDSC | DMDSC 是一个多实例、单数据库的系统。主要由数据库和数据库实例、共享存储、本地存储、通信网络、以及集群控制软件 DMCSS 组成,允许多个数据库实例同时访问、获得完整的数据库服务。 | 金融级高可用,自动负载均衡,应用高效迁移,高性能存储管理,企业级容灾,全面支持国产平台。 |
新一代分布式集群DMDPC | DMDPC 同时支持在线分析处理和在线事务处理,具备高可用、高扩展、高性能、高吞吐量、继承了 DM8 良好的兼容性,应用无需改造即可迁移到 DMDPC。 | 高可用,高可扩展,高性能,高吞吐量,透明易用。 |
参数 | 描述 |
---|---|
静态 | 可以被动态修改,需重启服务器生效。 |
动态 | 可以被动态修改,修改后即时生效;动态分为会话级和系统级:会话级:新参数值只影响新创建的会话,之前的会话不受影响;系统级:修改后会影响所有会话。 |
手动 | 不能动态修改,只能修改 dm.ini 然后重启。 |
定位执行效率低的 SQL 语句是 SQL 优化的第一步。待优化的 SQL 可大致分为两类:
SQL 执行时间在十几秒到数十秒之间,但执行频率不高,此类 SQL 对数据库整体性能影响并不大,可以放到最后进行优化。
SQL 单独执行时间可能很快,在几百毫秒到几秒之间,但执行频率非常高,甚至达到每秒上百次,高并发下执行效率降低,很可能导致系统瘫痪,此类 SQL 是优化的首要对象。
以下介绍两种定位慢 SQL 的方法,可记录下具体 SQL 语句以及对应执行时间,为后续 SQL 优化工作奠定基础。
跟踪日志文件是一个纯文本文件,以”dmsql_实例名_日期_时间命名.log”,默认生成在 DM 安装目录的 log 子目录下。跟踪日志内容包含系统各会话执行的 SQL 语句、参数信息、错误信息、执行时间等。跟踪日志主要用于分析错误和分析性能问题,基于跟踪日志可以对系统运行状态进行分析。(性能诊断中已介绍)
1. SQL 记录配置
当 INI 参数 ENABLE_MONITOR=1 打开时,显示系统最近 1000 条执行时间超过预定值的 SQL 语句,默认预定值为 1000 毫秒。
以上两个参数可通过 SP_SET_PARA_VALUE 系统函数修改,通过 SF_GET_PARA_VALUE 系统函数查看当前值。
--修改参数值
SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);
--查看参数值
select SF_GET_PARA_VALUE(1,'ENABLE_MONITOR');
2. 查询方式
(1)查询当前正在执行的会话信息。
SELECT * FROM (
SELECT 'SP_CLOSE_SESSION('||SESS_ID||');' AS CLOSE_SESSION,
DATEDIFF(SS,LAST_SEND_TIME,SYSDATE) sql_exectime,
TRX_ID,
CLNT_IP,
B.IO_WAIT_TIME AS IO_WAIT_TIME,
SF_GET_SESSION_SQL(SESS_ID) FULLSQL,
A.SQL_TEXT
FROM V$SESSIONS a,V$SQL_STAT B WHERE STATE IN ('ACTIVE','WAIT')
AND A.SESS_ID = B.SESSID
)
SQL_TEXT 列记录的是部分 SQL 语句;FULLSQL 列存储了完整的执行 SQL 语句。
(2)查询超过执行时间阈值的 SQL 语句。
可通过查询 V$LONG_EXEC_SQLS 系统视图获取结果:
SELECT * FROM V$LONG_EXEC_SQLS;
查询结果字段详细信息介绍如下表所示:
列名 | 说明 |
---|---|
SESS_ID | 会话 ID,会话唯一标识 |
SQL_ID | 语句 ID,语句唯一标识 |
SQL_TEXT | SQL 文本 |
EXEC_TIME | 执行时间(毫秒) |
FINISH_TIME | 执行结束时间 |
N_RUNS | 执行次数 |
SEQNO | 编号 |
TRX_ID | 事务号 |
1. 概述
简单来说,执行计划就是一条 SQL 语句在数据库中的执行过程或访问路径的描述。SQL 语言是种功能强大且非过程性的编程语言,比如以下这条 SQL 语句:
SELECT * FROM T1, T2 WHERE T1.ID = T2.ID AND T1.ID = 6;
开发人员只关心 SQL 语句能否返回 T1 与 T2 表的关联查询结果,不需要指定该 SQL 如何执行,也就是说不关心该 SQL 是先访问 T1 表还是先访问 T2 表。对于 SQL 来说,两种访问方式就是两个执行计划,查询优化器 (CBO) 将根据代价也就是开销来选择最优的执行计划。以如下 SQL 语句执行计划为例:
SELECT * FROM SYSOBJECTS;
1 #NSET2: [0, 1282, 396]
2 #PRJT2: [0, 1282, 396]; exp_num(17), is_atom(FALSE)
3 #CSCN2: [0, 1282, 396]; SYSINDEXSYSOBJECTS(SYSOBJECTS as SYSOBJECTS)
执行计划的每行即为一个计划节点,主要包含三部分信息。
第一部分 NEST2、PRJT2、CSCN2 为操作符及数据库具体执行了什么操作。
第二部分的三元组为该计划节点的执行代价,具体含义为[代价,记录行数,字节数]。
第三部分为操作符的补充信息。
例如:第三个计划节点表示操作符是 CSCN2(即全表扫描),代价估算是 0 ms,扫描的记录行数是 1282 行,输出字节数是 396 个。
各计划节点的执行顺序为:缩进越多的越先执行,同样缩进的上面的先执行,下面的后执行,上下的优先级高于内外。缩进最深的,最先执行;缩进深度相同的,先上后下。口诀:最右最上先执行。
#CSCN2: [1, 2, 12]; INDEX33555496(TEST)
操作符,[代价,行数,字节数] 描述
2. 查看执行计划
达梦数据库可通过两种方式查看执行计划。
方式一:通过 DM 数据库配套管理工具查看。
方式二:使用 explain 命令查看。
以下对两种查看方式进行介绍。
(1)管理工具查看执行计划
在 DM 配套管理工具中,选中待查看执行计划的 SQL 语句,点击工具栏中的按钮,或使用快捷键 F9,即可查看执行计划。
(2)使用 explain 命令查看执行计划
在待查看执行计划的 SQL 语句前加 explain 执行 SQL 语句即可查看预估的执行计划:
explain select * from sysobjects;
--执行计划
1 #NSET2: [1, 986, 396]
2 #PRJT2: [1, 986, 396]; exp_num(17), is_atom(FALSE)
3 #CSCN2: [1, 986, 396]; SYSINDEXSYSOBJECTS(SYSOBJECTS as SYSOBJECTS)
(3)使用 disql 命令行查真实执行计划
SQL> set autotrace traceonly
SQL> select * from sysobjects;
2348 rows got
1 #NSET2: [1, 2348->2348, 397]
2 #PRJT2: [1, 2348->2348, 397]; exp_num(17), is_atom(FALSE)
3 #CSCN2: [1, 2348->2348, 397]; SYSINDEXSYSOBJECTS(SYSOBJECTS)
Statistics
-----------------------------------------------------------------
0 data pages changed
0 undo pages changed
67 logical reads
0 physical reads
0 redo size
364191 bytes sent to client
155 bytes received from client
2 roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2348 rows processed
0 io wait time(ms)
2 exec time(ms)
重点关注 logical reads(逻辑读)和 physical reads(物理读)相应的指标值,并结合 rows processed 返回处理行数多少来分析。如果返回行数少(并且 bytes sent to client 总量不大),应尽可能减少 IO 开销,让执行计划选择正确的索引路径。
Sort(disk) 一般因排序( hash join 发生归并、order by、group by 场景)区内存不足,如果数据库服务器物理内存充足,可以适当上调排序区内存,尽量避免操作刷盘,否则会影响执行性能。
下面通过几个例子来介绍一些常见操作符。准备测试表及数据如下:
DROP TABLE T1;
DROP TABLE T2;
CREATE TABLE T1(C1 INT ,C2 CHAR(1),C3 VARCHAR(10) ,C4 VARCHAR(10) );
CREATE TABLE T2(C1 INT ,C2 CHAR(1),C3 VARCHAR(10) ,C4 VARCHAR(10) );
INSERT INTO T1
SELECT LEVEL C1,CHR(65+MOD(LEVEL,57)) C2,'TEST',NULL FROM DUAL
CONNECT BY LEVEL<=10000;
INSERT INTO T2
SELECT LEVEL C1,CHR(65+MOD(LEVEL,57)) C2,'TEST',NULL FROM DUAL
CONNECT BY LEVEL<=10000;
CREATE INDEX IDX_C1_T1 ON T1(C1);
SP_INDEX_STAT_INIT(USER,'IDX_C1_T1');
1. NSET:结果集收集
EXPLAIN SELECT * FROM T1;
1 #NSET2: [1, 10000, 156]
2 #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)
3 #CSCN2: [1, 10000, 156]; INDEX33556710(T1)
NSET 是用于结果集收集的操作符,一般是查询计划的顶层节点,优化工作中无需对该操作符过多关注,一般没有优化空间。
2. PRJT:投影
EXPLAIN SELECT * FROM T1;
1 #NSET2: [1, 10000, 156]
2 #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)
3 #CSCN2: [1, 10000, 156]; INDEX33556710(T1)
PRJT 是关系的【投影】 (project) 运算,用于选择表达式项的计算。广泛用于查询,排序,函数索引创建等。优化工作中无需对该操作符过多关注,一般没有优化空间。
3. SLCT:选择
EXPLAIN SELECT * FROM T1 WHERE C2='TEST';
1 #NSET2: [1, 250, 156]
2 #PRJT2: [1, 250, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 250, 156]; T1.C2 = TEST
4 #CSCN2: [1, 10000, 156]; INDEX33556717(T1)
SLCT 是关系的【选择】运算,用于查询条件的过滤。可比较返回结果集与代价估算中是否接近,如相差较大可考虑收集统计信息。若该过滤条件过滤性较好,可考虑在条件列增加索引。
4. AAGR:简单聚集
EXPLAIN SELECT COUNT(*) FROM T1 WHERE C1 = 10;
1 #NSET2: [0, 1, 4]
2 #PRJT2: [0, 1, 4]; exp_num(1), is_atom(FALSE)
3 #AAGR2: [0, 1, 4]; grp_num(0), sfun_num(1)
4 #SSEK2: [0, 1, 4]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]
AAGR 用于没有 GROUP BY 的 COUNT、SUM、AGE、MAX、MIN 等聚集函数的计算。
5. FAGR:快速聚集
EXPLAIN SELECT MAX(C1) FROM T1;
1 #NSET2: [1, 1, 0]
2 #PRJT2: [1, 1, 0]; exp_num(1), is_atom(FALSE)
3 #FAGR2: [1, 1, 0]; sfun_num(1)
FAGR 用于没有过滤条件时,从表或索引快速获取 MAX、MIN、COUNT 值。
6. HAGR:HASH 分组聚集
EXPLAIN SELECT COUNT(*) FROM T1 GROUP BY C2;
1 #NSET2: [1, 100, 48]
2 #PRJT2: [1, 100, 48]; exp_num(1), is_atom(FALSE)
3 #HAGR2: [1, 100, 48]; grp_num(1), sfun_num(1)
4 #CSCN2: [1, 10000, 48]; INDEX33556717(T1)
HAGR 用于分组列没有索引只能走全表扫描的分组聚集,该示例中 C2 列没有创建索引。
7. SAGR:流分组聚集
EXPLAIN SELECT COUNT(*) FROM T1 GROUP BY C1;
1 #NSET2: [1, 100, 4]
2 #PRJT2: [1, 100, 4]; exp_num(1), is_atom(FALSE)
3 #SAGR2: [1, 100, 4]; grp_num(1), sfun_num(1)
4 #SSCN: [1, 10000, 4]; IDX_C1_T1(T1)
SAGR 用于分组列是有序的情况下,可以使用流分组聚集,C1 列上已经创建了索引,SAGR2 性能优于 HAGR2。
8. BLKUP:二次扫描 (回表)
EXPLAIN SELECT * FROM T1 WHERE C1=10;
1 #NSET2: [0, 1, 156]
2 #PRJT2: [0, 1, 156]; exp_num(5), is_atom(FALSE)
3 #BLKUP2: [0, 1, 156]; IDX_C1_T1(T1)
4 #SSEK2: [0, 1, 156]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]
BLKUP 先使用二级索引索引定位 rowid,再根据表的主键、聚集索引、rowid 等信息获取数据行中其它列。
9. CSCN:全表扫描
EXPLAIN SELECT * FROM T1;
1 #NSET2: [1, 10000, 156]
2 #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)
3 #CSCN2: [1, 10000, 156]; INDEX33556710(T1)
CSCN2 是 CLUSTER INDEX SCAN 的缩写即通过聚集索引扫描全表,全表扫描是最简单的查询,如果没有选择谓词,或者没有索引可以利用,则系统一般只能做全表扫描。全表扫描 I/O 开销较大,在一个高并发的系统中应尽量避免全表扫描。
10. SSEK、CSEK、SSCN:索引扫描
-- 创建所需索引
CREATE CLUSTER INDEX IDX_C1_T2 ON T2(C1);
CREATE INDEX IDX_C1_C2_T1 ON T1(C1,C2);
(1)SSEK
EXPLAIN SELECT * FROM T1 WHERE C1=10;
1 #NSET2: [0, 1, 156]
2 #PRJT2: [0, 1, 156]; exp_num(5), is_atom(FALSE)
3 #BLKUP2: [0, 1, 156]; IDX_C1_T1(T1)
4 #SSEK2: [0, 1, 156]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]
SSEK2 是二级索引扫描即先扫描索引,再通过主键、聚集索引、rowid 等信息去扫描表。
(2)CSEK
EXPLAIN SELECT * FROM T2 WHERE C1=10;
1 #NSET2: [0, 250, 156]
2 #PRJT2: [0, 250, 156]; exp_num(5), is_atom(FALSE)
3 #CSEK2: [0, 250, 156]; scan_type(ASC), IDX_C1_T2(T2), scan_range[10,10]
CSEK2 是聚集索引扫描只需要扫描索引,不需要扫描表,即无需 BLKUP 操作,如果 BLKUP 开销较大时,可考虑创建聚集索引。
(3)SSCN
EXPLAIN SELECT C1,C2 FROM T1;
1 #NSET2: [1, 10000, 60]
2 #PRJT2: [1, 10000, 60]; exp_num(3), is_atom(FALSE)
3 #SSCN: [1, 10000, 60]; IDX_C1_C2_T1(T1)
SSCN 是索引全扫描,不需要扫描表。
11. NEST LOOP:嵌套循环连接
嵌套循环连接是最基础的连接方式,将一张表(驱动表)的每一个值与另一张表(被驱动表)的所有值拼接,形成一个大结果集,再从大结果集中过滤出满足条件的行。驱动表的行数就是循环的次数,将在很大程度上影响执行效率。
连接列是否有索引,都可以走 NEST LOOP,但没有索引,执行效率会很差,语句如下所示:
select /*+use_nl(t1,t2)*/* from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';
1 #NSET2: [17862, 24725, 296]
2 #PRJT2: [17862, 24725, 296]; exp_num(8), is_atom(FALSE)
3 #SLCT2: [17862, 24725, 296]; T1.C1 = T2.C1
4 #NEST LOOP INNER JOIN2: [17862, 24725, 296];
5 #SLCT2: [1, 250, 148]; T1.C2 = 'A'
6 #CSCN2: [1, 10000, 148]; INDEX33555594(T1)
7 #CSCN2: [1, 10000, 148]; INDEX33555595(T2)
可针对 T1 和 T2 的连接列创建索引,并收集统计信息,语句如下所示:
CREATE INDEX IDX_T1_C2 ON T1(C2);
CREATE INDEX IDX_T2_C1 ON T2(C1);
DBMS_STATS.GATHER_INDEX_STATS(USER,'IDX_T1_C2');
DBMS_STATS.GATHER_INDEX_STATS(USER,'IDX_T2_C1');
再次查看执行计划可看出效率明显改善,代价有显著下降,语句如下所示:
select /*+use_nl(t1,t2)*/* from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';
1 #NSET2: [9805, 17151, 296]
2 #PRJT2: [9805, 17151, 296]; exp_num(8), is_atom(FALSE)
3 #SLCT2: [9805, 17151, 296]; T1.C1 = T2.C1
4 #NEST LOOP INNER JOIN2: [9805, 17151, 296];
5 #BLKUP2: [1, 175, 148]; IDX_T1_C2(T1)
6 #SSEK2: [1, 175, 148]; scan_type(ASC), IDX_T1_C2(T1), scan_range['A','A']
7 #CSCN2: [1, 10000, 148]; INDEX33555585(T2)
适用场景:
驱动表有很好的过滤条件
表连接条件能使用索引
结果集比较小
12. HASH JOIN:哈希连接
哈希连接是在没有索引或索引无法使用情况下大多数连接的处理方式。哈希连接使用关联列去重后结果集较小的表做成 HASH 表,另一张表的连接列在 HASH 后向 HASH 表进行匹配,这种情况下匹配速度极快,主要开销在于对连接表的全表扫描以及 HASH 运算。
select * from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';
1 #NSET2: [4, 24502, 296]
2 #PRJT2: [4, 24502, 296]; exp_num(8), is_atom(FALSE)
3 #HASH2 INNER JOIN: [4, 24502, 296]; KEY_NUM(1); KEY(T1.C1=T2.C1) KEY_NULL_EQU(0)
4 #SLCT2: [1, 250, 148]; T1.C2 = 'A'
5 #CSCN2: [1, 10000, 148]; INDEX33555599(T1)
6 #CSCN2: [1, 10000, 148]; INDEX33555600(T2)
哈希连接比较消耗内存如果系统有很多这种连接时,需调整以下 3 个参数:
以下是生成的表格:
参数名 | 说明 |
---|---|
HJ_BUF_GLOBAL_SIZE | HASH 连接操作符的数据总缓存大小(>= HJ_BUF_SIZE),系统级参数,以兆为单位。有效值范围(10~500000) |
HJ_BUF_SIZE | 单个哈希连接操作符的数据总缓存大小,以兆为单位。有效值范围(2~100000) |
HJ_BLK_SIZE | 哈希连接操作符每次分配缓存(BLK)大小,以兆为单位,必须小于 HJ_BUF_SIZE。有效值范围(1~50) |
13. MERGE JOIN:归并排序连接
归并排序连接需要两张表的连接列都有索引,对两张表扫描索引后按照索引顺序进行归并。
-- 对连接列创建索引
CREATE INDEX IDX_T1_C1C2 ON T1(C1,C2);
Copy
select /*+use_merge(t1 t2)*/t1.c1,t2.c1 from t1 inner join t2 on t1.c1=t2.c1 where t2.c2='b';
1 #NSET2: [13, 24725, 56]
2 #PRJT2: [13, 24725, 56]; exp_num(2), is_atom(FALSE)
3 #SLCT2: [13, 24725, 56]; T2.C2 = 'b'
4 #MERGE INNER JOIN3: [13, 24725, 56]; KEY_NUM(1); KEY(COL_0 = COL_0) KEY_NULL_EQU(0)
5 #SSCN: [1, 10000, 4]; IDX_C1_T1(T1)
6 #BLKUP2: [1, 10000, 52]; IDX_T2_C1(T2)
7 #SSCN: [1, 10000, 52]; IDX_T2_C1(T2)
关于查询语句,有以下几点特征:
返回数据越多,语句执行时间越长;
分页是一个优化重点,order by 排序大小由结果集大小决定,过大会在临时表空间排序,性能降低;
一些语句会隐式排序,比如 uinon group by;
buffer 过小,数据页频繁的换入换出。
关于优化 sql 语句:
通过各种手段减少 sql 执行过程中的 IO 代价,内存中的计算,临时表使用等;
表与表之间的关系,即关联条件之间的数据对应关系;
表数据量大小,对于 OLTP 是否满足小表驱动大表;
sql 返回结果集多少,如果返回结果集少,sql 优化余地较大;
合理利用索引(组合索引)的特点,虽然维护索引也需要代价,但是对于查询来说,很多时候效果立竿见影。
关于访问和连接方法:
全表扫描访问;
索引扫描访问;
嵌套循环连接;
哈希连接;
归并连接;
半连接、反连接;
n 张表至少有 n-1 次连接。
索引
索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录。
SQL 语句改写
优化 GROUP BY
提高 GROUP BY 语句的效率,可以在 GROUP BY 之前过滤掉不需要的内容。
--优化前
SELECT JOB,AVG(AGE) FROM TEMP
GROUP BY JOB HAVING JOB = 'STUDENT' OR JOB = 'MANAGER';
--优化后
SELECT JOB,AVG(AGE) FROM TEMP
WHERE JOB = 'STUDENT' OR JOB = 'MANAGER' GROUP BY JOB;
用 UNION ALL 替换 UNION
当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果集合会以 UNION ALL 的方式被合并,在输出最终结果前进行排序。用 UNION ALL 替代 UNION, 这样排序就不必要了,效率就会因此得到提高。
--优化前
SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'
UNION
SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';
--优化后
SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'
UNION ALL
SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';
用 EXISTS 替换 DISTINCT
当 SQL 包含一对多表查询时,避免在 SELECT 子句中使用 DISTINCT,一般用 EXISTS 替换 DISTINCT 查询更为迅速。
--优化前
SELECT DISTINCT USER_ID,BILL_ID FROM USER_TAB1 D,USER_TAB2 E
WHERE D.USER_ID= E.USER_ID;
--优化后
SELECT USER_ID,BILL_ID FROM USER_TAB1 D WHERE EXISTS(SELECT 1 FROM USER_TAB2 E WHERE E.USER_ID= D.USER_ID);
多使用 COMMIT
可以在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放的资源而减少。
COMMIT 所释放的资源:
回滚段上用于恢复数据的信息;
被程序语句获得的锁;
redo log buffer 中的空间;
为管理上述 3 种资源中的内部花销。
用 WHERE 子句替换 HAVING 子句
避免使用 HAVING 子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、总计等操作,可以通过 WHERE 子句限制记录的数目。on、where、having 三个都可以加条件子句,其中,on 是最先执行,where 次之,having 最后。
on 是先把不符合条件的记录过滤后才进行统计,在两个表联接时才用 on;
在单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,where 和 having 结果是一样的,但 where 比 having 快;
如果涉及到计算字段,where 的作用时间是在计算之前完成,而 having 是在计算后才起作用,两者的结果会不同;
在多表联接查询时,on 比 where 更早起作用。首先会根据各个表之间的关联条件,把多个表合成一个临时表后,由 where 进行过滤再计算,计算完再由 having 进行过滤。
用 TRUNCATE 替换 DELETE
当删除表中的记录时,在通常情况下, 回滚段用来存放可以被恢复的信息。如果没有 COMMIT 事务,会将数据恢复到执行删除命令之前的状况;而当运用 TRUNCATE 时,回滚段不再存放任何可被恢复的信息。当命令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短。
EXISTS 替换 IN、用 NOT EXISTS 替换 NOT IN
在基于基础表的查询中可能会需要对另一个表进行联接。在这种情况下, 使用 EXISTS (或 NOT EXISTS )通常将提高查询的效率。在子查询中,NOT IN 子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN 都是最低效的(要对子查询中的表执行一个全表遍历),所以尽量将 NOT IN 改写成外连接( Outer Joins )或 NOT EXISTS。
--优化前
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
AND A.ID IN(SELECT ID FROM TEMP1 WHERE NAME ='TOM');
--优化后
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
AND EXISTS(SELECT 1 FROM TEMP1 WHERE A.ID= ID AND NAME='TOM');
半连接优化
半连接也是子查询的一种,查询只返回主表数据,子查询作为条件过滤使用。exists 关注是否有返回行,取决于关联列,in 关注是否存在过滤数据,在半连接改写中理解这点很重要。
优化改写:半连接改 join 。
--改写前,已下两种写法特征就是执行计划出现 semi 关键字
--写法一:
select EMPNO, ENAME, JOB, MGR, HIREDATE
from emp2
where deptno in (select deptno from dept2)
--写法二:
select EMPNO, ENAME, JOB, MGR, HIREDATE
from emp2
where exists (select deptno from dept2 where dept2.deptno = emp2.deptno)
--改写优化
--当子查询中部门表中部门编号不存在重复改写如下:
select emp2.EMPNO,
emp2.ENAME,
emp2.JOB,
emp2.MGR,
emp2.HIREDATE
from emp2
inner join dept2
on dept2.deptno = emp2.deptno
--若存在数据重复先根据关联列去重再关联
select dept2.*
from (select distinct deptno from emp2) emp2
inner join dept2
on dept2.deptno = emp2.deptno
反连接优化
同半连接一样,查询也只返回主表数据,通过 not in 和 not exists 过滤,再改写的过程中特别要注意反连接 not in 对空值敏感。
--ept2 deptno 列不存在空值时,以下两种写法等价,当 not in 存在空时,无数据行返回,因此 not exists 改写 not in 需要加上 not is null
select * from emp2 where deptno not in (select deptno from dept2);
select * from emp2 e where not exists (select * from dept2 d where d.deptno = e.deptno)
--not in、 not exists 改写 left join
select * from emp2 E where deptno not in (select deptno from dept2 D)
--反连接驱动是 E 表,被驱动是 D 表,所以改写 left join ,not in 表示不在此范围,即 emp2 有的部门编号,dept2 没有
--左连接会将右表没有的内容用 NULL 表示,所以关联后取 d.deptno is null 过滤
select e.*
from emp2 e
left join dept2 d
on d.deptno = e.deptno
where d.deptno is null
表设计优化
表设计优化可以从三个方面入手:选择合适的表类型、设置分区表、设置全局临时表。
表类型 | 描述 | 主要特征 | 适用场景 |
---|---|---|---|
行存储表 | 以记录为单位存储,数据页面中保存完整的若干条记录 | 1. 按行存储<br>2. 每个表创建一个B树,叶子节点存放数据 | 适用于高并发OLTP场景 |
列存储表(HUGE) | 以列为单位存储,同一列的所有行数据连续存放,指定页面存储单一列的连续数据 | 1. 按列存储<br>2. 分为非事务型(LOG NONE/LAST/ALL)和事务型HUGE表 | 适用于海量数据分析场景 |
堆表 | 采用物理ROWID形式存储,通过文件号、页号和页内偏移定位数据,无需额外存储ROWID | 1. 数据页以链表形式存储<br>2. 支持设置并发分支 | 并发插入性能较高的场景 |
分区类型
核心优势
TRUNCATE
、DROP
、ADD
、EXCHANGE
,便于数据维护。类型
ON COMMIT DELETE ROWS
)ON COMMIT PRESERVE ROWS
)核心优势
hint 优化 sql
当统计信息已收集,且索引也按照需求建立,sql 执行效率仍然不符合预期,可以考虑添加 hint 方式来进行优化。
统计信息概述
统计信息主要是描述数据库中表和索引的大小数以及数据分布状况等的一类信息。比如:表的行数、块数、平均每行的大小、索引的高度、叶子节点数以及索引字段的行数等。
统计信息对于 CBO(基于代价的优化器)生成执行计划具有直接影响。例如在嵌套循环连接(链接)中需要选择小表作为驱动表,两个关联表哪个是小表完全取决于统计信息中记录的数据量信息。此外,访问一个表是否要走索引,关联查询能否采用其它关联方式等都是 CBO 基于统计信息确定的。因此,统计信息的准确是生成最优执行计划的必要前提。
收集统计信息
DM 收集统计信息的方法分为手动收集和自动收集。
手动收集
--收集指定用户下所有表所有列的统计信息:
DBMS_STATS.GATHER_SCHEMA_STATS('username',100,TRUE,'FOR ALL COLUMNS SIZE AUTO');
--收集指定用户下所有索引的统计信息:
DBMS_STATS.GATHER_SCHEMA_STATS('usename',1.0,TRUE,'FOR ALL INDEXED SIZE AUTO');
--或 收集单个索引统计信息:
DBMS_STATS.GATHER_INDEX_STATS('username','IDX_T2_X');
--收集指定用户下某表统计信息:
DBMS_STATS.GATHER_TABLE_STATS('username','table_name',null,100,TRUE,'FOR ALL COLUMNS SIZE AUTO');
--收集某表某列的统计信息:
STAT 100 ON table_name(column_name);
注意
统计信息收集过程中将对数据库性能造成一定影响,避免在业务高峰期收集统计信息。
自动收集
DM 数据库支持统计信息的自动收集,当全表数据量变化超过设定阈值后可自动更新统计信息。
--打开表数据量监控开关,参数值为 1 时监控所有表,2 时仅监控配置表
SP_SET_PARA_VALUE(1,'AUTO_STAT_OBJ',2);
--设置 SYSDBA.T 表数据变化率超过 15% 时触发自动更新统计信息
DBMS_STATS.SET_TABLE_PREFS('SYSDBA','T','STALE_PERCENT',15);
--配置自动收集统计信息触发时机
SP_CREATE_AUTO_STAT_TRIGGER(1, 1, 1, 1,'14:36', '2020/3/31',60,1);
/*
函数各参数介绍
SP_CREATE_AUTO_STAT_TRIGGER(
TYPE INT, --间隔类型,默认为天
FREQ_INTERVAL INT, --间隔频率,默认 1
FREQ_SUB_INTERVAL INT, --间隔频率,与 FREQ_INTERVAL 配合使用
FREQ_MINUTE_INTERVAL INT, --间隔分钟,默认为 1440
STARTTIME VARCHAR(128), --开始时间,默认为 22:00
DURING_START_DATE VARCHAR(128), --重复执行的起始时间,默认 1900/1/1
MAX_RUN_DURATION INT, --允许的最长执行时间(秒),默认不限制
ENABLE INT --0 关闭,1 启用 --默认为 1
);
*/
查看统计信息
--用于经过 GATHER_TABLE_STATS、GATHER_INDEX_STATS 或 GATHER_SCHEMA_STATS 收集之后展示。
dbms_stats.table_stats_show('模式名','表名');
--用于经过 GATHER_TABLE_STATS、GATHER_INDEX_STATS 或 GATHER_SCHEMA_STATS 收集之后展示。 返回两个结果集:一个是索引的统计信息;另一个是直方图的统计信息。
dbms_stats.index_stats_show('模式名','索引名');
--用于经过 GATHER_TABLE_STATS、GATHER_INDEX_STATS 或 GATHER_SCHEMA_STATS 收集之后展示。
dbms_stats.COLUMN_STATS_SHOW('模式名','表名','列名');
更新统计信息
--更新已有统计信息
DBMS_STATS.UPDATE_ALL_STATS();
删除统计信息
--表
DBMS_STATS.DELETE_TABLE_STATS('模式名','表名','分区名',...);
--模式
DBMS_STATS.DELETE_SCHMA_STATS('模式名','','',...);
--索引
DBMS_STATS.DELETE_INDEX_STATS('模式名','索引名','分区表名',...);
--字段
DBMS_STATS.DELETE_COLUMN_STATS('模式名','表名','列名','分区表名',...);
文章
阅读量
获赞