数据库监控脚本(一)

 

 

第一章数据库监控脚本(一)

2007 12 29 星期六 11:27一、数据库构架体系

1、表空间的监控

2、监控表空间使用率与剩余空间大小的语句

3、表空间是否具有自动扩展空间的能力

4、使用字典管理的表空间哪些表的扩展将引起表空间的扩展

5、段的占用空间与区间数

6、重建索引

7、监控表是否有主键

二、性能监控

1、数据缓冲区的命中率

2、库缓冲说明了SQL语句的重载率,越低越好

3、用户锁

4、锁与等待,查询谁锁了表,而谁在等待

5、发生了事务或锁,查找使用的回滚段

6、哪个用户正在利用临时段吗?

7、在ORACLE 9i中,可以监控索引的使用,开始索引监控与停止索引监控的脚本

8、通过sid找到os进程号(Check OS process id from Oracle sid

9、通过os进程找sidCheck Oracle sid from OS process id

10、通过sidsql语句(Check current SQL in a session

11、找等待事件Checking v$session_wait

12、数据缓冲区GETMISS相对gets的比例Dictionary Cache Hits MISS RATIO

13、通过文件号及块号找对应数据库对象Check DB object name from file id and block#

14、寻找hot block

15、找出每个文件上的等待事件

16、找出引起等待事件的SQL语句.

17、监控共享池中哪个对象引起了大的内存分配

 

1、表空间的监控

SELECT TABLESPACE_NAME,INITIAL_EXTENT,NEXT_EXTENT,MIN_EXTENTS,

MAX_EXTENTS,PCT_INCREASE,MIN_EXTLEN,STATUS,

CONTENTS,LOGGING,

EXTENT_MANAGEMENT, -- Columns not available in v8.0.x

ALLOCATION_TYPE, -- Remove these columns if running

PLUGGED_IN, -- against a v8.0.x database

SEGMENT_SPACE_MANAGEMENT --use only in v9.2.x or later

FROM DBA_TABLESPACES

ORDER BY TABLESPACE_NAME;

 

2、监控表空间使用率与剩余空间大小的语句

SELECT D.TABLESPACE_NAME,SPACE "SUM_SPACE(M)",

BLOCKS SUM_BLOCKS,SPACE-NVL(FREE_SPACE,0) "USED_SPACE(M)",

ROUND((1-NVL(FREE_SPACE,0)/SPACE)*100,2) "USED_RATE(%)",

FREE_SPACE "FREE_SPACE(M)"

FROM

(SELECT TABLESPACE_NAME,

ROUND(SUM(BYTES)/(1024*1024),2) SPACE,

SUM(BLOCKS) BLOCKS

FROM DBA_DATA_FILES

GROUP BY TABLESPACE_NAME) D,

(SELECT TABLESPACE_NAME,ROUND(SUM(BYTES)/(1024*1024),2) FREE_SPACE

FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) F

WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME(+)

UNION ALL

SELECT D.TABLESPACE_NAME,SPACE "SUM_SPACE(M)",BLOCKS SUM_BLOCKS,

USED_SPACE "USED_SPACE(M)",ROUND(NVL(USED_SPACE,0)/SPACE*100,2) "USED_RATE(%)",

NVL(FREE_SPACE,0) "FREE_SPACE(M)"

FROM (SELECT TABLESPACE_NAME,ROUND(SUM(BYTES)/(1024*1024),2) SPACE,

SUM(BLOCKS) BLOCKS FROM DBA_TEMP_FILES

GROUP BY TABLESPACE_NAME) D,

(SELECT TABLESPACE_NAME,ROUND(SUM(BYTES_USED)/(1024*1024),2) USED_SPACE,

ROUND(SUM(BYTES_FREE)/(1024*1024),2) FREE_SPACE

FROM V$TEMP_SPACE_HEADER GROUP BY TABLESPACE_NAME) F

WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME(+);

 

3、表空间是否具有自动扩展空间的能力

SELECT T.TABLESPACE_NAME,D.FILE_NAME,D.AUTOEXTENSIBLE,D.BYTES,D.MAXBYTES,D.STATUS

FROM DBA_TABLESPACES T,DBA_DATA_FILES D

WHERE T. TABLESPACE_NAME =D. TABLESPACE_NAME

ORDER BY TABLESPACE_NAME,FILE_NAME;

 

4、使用字典管理的表空间哪些表的扩展将引起表空间的扩展。

SELECT A.OWNER,A.TABLE_NAME,A.NEXT_EXTENT,A.TABLESPACE_NAME

FROM ALL_TABLES A,

(SELECT TABLESPACE_NAME, MAX(BYTES) BIG_CHUNK

FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) F

WHERE F.TABLESPACE_NAME = A.TABLESPACE_NAME

AND A.NEXT_EXTENT > F.BIG_CHUNK;

 

5、段的占用空间与区间数也是很需要注意的一个问题,如果一个段的占用空间太大,或者跨越太多的区间(在字典管理的表空间中,将有严重的性能影响),

如果段没有可以再分配的区间,将导致数据库错误。所以,段的大小与区间监控也是一个很重要的工作

SELECT S.OWNER,S.SEGMENT_NAME,S.SEGMENT_TYPE,S.PARTITION_NAME,

ROUND(BYTES/(1024*1024),2) "USED_SPACE(M)",

EXTENTS USED_EXTENTS,S.MAX_EXTENTS,

S.BLOCKS ALLOCATED_BLOCKS,

S.BLOCKS USED_BOLCKS,

S.PCT_INCREASE,

S.NEXT_EXTENT/1024 "NEXT_EXTENT(K)"

FROM DBA_SEGMENTS S

WHERE S.OWNER NOT IN ('SYS','SYSTEM')

ORDER BY Used_Extents DESC;

 

6、重建索引

数据库的索引如果有比较频繁的Delete操作,将可能导致索引产生很多碎片,所以,在有的时候,需要对所有的索引重新REBUILD,以便合并索引块,减少碎片,提高查询速度。

SQL> set heading off

SQL> set feedback off

SQL> spool d:index.sql

SQL>

SELECT 'alter index ' || index_name || ' rebuild '

||'tablespace INDEXES storage(initial 256K next 256K pctincrease 0);'

FROM all_indexes

WHERE ( tablespace_name != 'INDEXES' OR next_extent != ( 256 * 1024 ) )

AND owner = USER

SQL>spool off

 

这个时候,我们打开spool出来的文件,就可以直接运行了。

 

7、监控表是否有主键

SELECT table_name

FROM all_tables

WHERE owner = USER

MINUS

SELECT table_name

FROM all_constraints

WHERE owner = USER

AND constraint_type = 'P';

 

二、性能监控

 

1、数据缓冲区的命中率

SELECT a.VALUE + b.VALUE logical_reads,

c.VALUE phys_reads,

round(100*(1-c.value/(a.value+b.value)),4) hit_ratio

FROM v$sysstat a,v$sysstat b,v$sysstat c

WHERE a.NAME='db block gets'

AND b.NAME='consistent gets'

AND c.NAME='physical reads' ;

 

2、库缓冲说明了SQL语句的重载率,越低越好

SELECT SUM(pins) total_pins,SUM(reloads) total_reloads,

SUM(reloads)/SUM(pins)*100 libcache_reload_ratio

FROM v$librarycache;

 

3、用户锁

任何DML语句其实产生了两个锁,一个是表锁,一个是行锁。

可以通过alter system kill session sid,serial#’来杀掉会话

SELECT /*+ rule */ s.username, decode(l.type,'TM','TABLE LOCK','TX','ROW LOCK',

NULL) LOCK_LEVEL, o.owner,o.object_name,o.object_type,

s.sid,s.serial#,s.terminal,s.machine,s.program,s.osuser

FROM v$session s,v$lock l,dba_objects o

WHERE l.sid = s.sid

AND l.id1 = o.object_id(+)

AND s.username is NOT NULL

 

4、锁与等待,查询谁锁了表,而谁在等待

SELECT /*+ rule */ lpad(' ',decode(l.xidusn ,0,3,0))||l.oracle_username User_name,

o.owner,o.object_name,o.object_type,s.sid,s.serial#

FROM v$locked_object l,dba_objects o,v$session s

WHERE l.object_id=o.object_id

AND l.session_id=s.sid

ORDER BY o.object_id,xidusn DESC;

以上查询结果是一个树状结构,如果有子节点,则表示有等待发生。如果想知道锁用了哪个回滚段,还可以关联到V$rollname,其中xidusn就是回滚段的USN

 

5、发生了事务或锁,查找使用的回滚段

其实通过事务表,我们可以详细的查询到事务与回滚段之间的关系。

同时,如果关联会话表,我们则可以知道是哪个会话发动了这个事务。

SELECT s.USERNAME,s.SID,s.SERIAL#,t.UBAFIL "UBA filenum",

t.UBABLK "UBA Block number",t.USED_UBLK "Number os undo Blocks Used",

t.START_TIME,t.STATUS,t.START_SCNB,t.XIDUSN RollID,r.NAME RollName

FROM v$session s,v$transaction t,v$rollname r

WHERE s.SADDR=t.SES_ADDR

AND t.XIDUSN=r.usn;

 

6、哪个用户正在利用临时段吗?

SELECT b.tablespace, b.segfile#, b.segblk#, b.blocks, a.sid, a.serial#,

a.username, a.osuser, a.status,c.sql_text

FROM v$session a,v$sort_usage b, v$sql c

WHERE a.saddr = b.session_addr

AND a.sql_address = c.address(+)

ORDER BY b.tablespace, b.segfile#, b.segblk#, b.blocks;

 

7、在ORACLE 9i中,可以监控索引的使用,开始索引监控与停止索引监控的脚本

set heading off

set echo off

set feedback off

set pages 10000

spool start_index_monitor.sql

SELECT 'alter index '||owner||'.'||index_name||' monitoring usage;'

FROM dba_indexes

WHERE owner = USER;

spool off

set heading on

set echo on

set feedback on ------------------------------------------------

set heading off

set echo off

set feedback off

set pages 10000

spool stop_index_monitor.sql

SELECT 'alter index '||owner||'.'||index_name||' nomonitoring usage;'

FROM dba_indexes WHERE owner = USER;

spool off

set heading on

set echo on

set feedback on

 

如果需要监控更多的用户,可以将owner=User改写成别的

监控结果在视图v$object_usage中查询

 

8Check OS process id from Oracle sid

select spid from v$process

where addr in

( select paddr from v$session where sid=&sid) ;

 

9Check Oracle sid from OS process id

select sid from v$session

where paddr in ( select addr from v$process where spid=&pid) ;

 

10Check current SQL in a session

select SQL_TEXT

from V$SQLTEXT

where HASH_VALUE

= ( select SQL_HASH_VALUE from v$session

where sid = &sid)

order by PIECE;

 

11Checking v$session_wait

select * from v$session_wait

where event not like 'rdbms%'

and event not like 'SQL*N%'

and event not like '%timer';

 

12Dictionary Cache Hits

SELECT sum(getmisses)/sum(gets) FROM v$rowcache; /*It should be < 15%, otherwise Add share_pool_size*/

 

13Check DB object name from file id and block#

select owner,segment_name,segment_type

from dba_extents

where file_id = &fno

and &dno between block_id

and block_id + blocks – 1 ;

 

14、寻找hot block

select /*+ ordered */

e.owner ||'.'|| e.segment_name segment_name,

e.extent_id extent#,

x.dbablk - e.block_id + 1 block#,

x.tch,

l.child#

from sys.v$latch_children l, sys.x$bh x, sys.dba_extents e

where l.name = 'cache buffers chains'

and l.sleeps > &sleep_count

and x.hladdr = l.addr

and e.file_id = x.file#

and x.dbablk between e.block_id

and e.block_id + e.blocks - 1;

 

15、找出每个文件上的等待事件

select df.name,kf.count from v$datafile df,x$kcbfwait kf where (kf.indx+1)=df.file#;

 

16、找出引起等待事件的SQL语句.

select sql_text from v$sqlarea a,v$session b,v$session_wait c where a.address=b.sql_address and b.sid=c.sid and c.event=&ll;

 

17、监控共享池中哪个对象引起了大的内存分配

SELECT * FROM X$KSMLRU WHERE ksmlrsiz > 0;

 

 

第二章数据库监控脚本(二)

2007 12 29 星期六 11:48--1、查找trace文件

--2session下的重做数量

--3、估算自数据库启动以来每天的平均日志量

--4、估算日志数量

--5、查找隐含参数

--6、创建session的重做日志视图

--7、一致性读取的段及数据块信息

--8、等待事件分类及数量

--9、根据sid找到相应的sql语句

--10、系统自启动以来的累计等待时间前十名

--11、查找全表扫描(full scan)及快速全索引扫描(fast full index)

--12、通过具体的等待事件查找到有问题的sql语句(输入参数等待事件如:free buffer waits)

--13、查找数据库最繁忙的buffer

--14、查找热点buffer来自哪些对象

--15、关于latch信息

--16、具体热点块的latchbuffer信息及找到相应对象的sql语句

--17、创建临时表保存X$KSMSP的状态

--18、找出library cache pin等待的原因

--19、获得参数的描述信息

--20oracle收集的buffer cacheshared pool 的建议信息

--21、是 10g 中,决定各参数组件大小的查询

--22 10g 各动态组件调整时间及调整类型

--23sql在工作区中工作方式所占比例

--24pga动态性能视图信息

--25、获得存在问题的sql,根据pid

--26fast_start_mttr_target

--27、实例恢复的时间计算

--28show_space过程及使用

--29、分析表

--30unix环境快速shutdown数据库之前先删除各个进程

 

--1、查找trace文件

SELECT d.VALUE

|| '/'

|| LOWER (RTRIM (i.INSTANCE, CHR (0)))

|| '_ora_'

|| p.spid

|| '.trc' trace_file_name

FROM (SELECT p.spid

FROM SYS.v$mystat m, SYS.v$session s, SYS.v$process p

WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p,

(SELECT t.INSTANCE

FROM SYS.v$thread t, SYS.v$parameter v

WHERE v.NAME = 'thread'

AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,

(SELECT VALUE

FROM SYS.v$parameter

WHERE NAME = 'user_dump_dest') d

/

 

--2session下的重做数量

col name for a30

select a.name,b.value

from v$statname a,v$mystat b

where a.STATISTIC# = b.STATISTIC# and a.name = 'redo size';

 

--3、估算自数据库启动以来每天的平均日志量

alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

 

select startup_time from v$instance;

 

select (select value/1024/1024/1024 from v$sysstat where name='redo size')/

(select round(sysdate - ( select startup_time from v$instance)) from dual) REDO_GB_PER_DAY

from dual;

 

--4、估算日志数量

--一段时间的

SELECT NAME, completion_time, blocks * block_size / 1024 / 1024 mb

FROM v$archived_log

WHERE ROWNUM < 11

AND completion_time BETWEEN TRUNC (SYSDATE) - 2 AND TRUNC (SYSDATE) - 1

/

--每日全天的

SELECT TRUNC (completion_time), SUM (mb) / 1024 day_gb

FROM (SELECT NAME, completion_time, blocks * block_size / 1024 / 1024 mb

FROM v$archived_log

WHERE completion_time BETWEEN TRUNC (SYSDATE) - 2 AND TRUNC (SYSDATE) - 1)

GROUP BY TRUNC (completion_time)

/

--最近日期的日志生成统计

SELECT TRUNC (completion_time), SUM (mb) / 1024 day_gb

FROM (SELECT NAME, completion_time, blocks * block_size / 1024 / 1024 mb

FROM v$archived_log)

GROUP BY TRUNC (completion_time)

order by 1

/

 

--5、查找隐含参数

set linesize 132

column name format a30

column value format a25

select

x.ksppinm name,

y.ksppstvl value,

y.ksppstdf isdefault,

decode(bitand(y.ksppstvf,7),1,'MODIFIED',4,'SYSTEM_MOD','FALSE') ismod,

decode(bitand(y.ksppstvf,2),2,'TRUE','FALSE') isadj

from

sys.x$ksppi x,

sys.x$ksppcv y

where

x.inst_id = userenv('Instance') and

y.inst_id = userenv('Instance') and

x.indx = y.indx and

x.ksppinm like '%_&par%'

order by

translate(x.ksppinm, ' _', ' ')

/

 

--6、创建session的重做日志视图

CREATE OR REPLACE VIEW redo_size

AS

SELECT VALUE

FROM v$mystat, v$statname

WHERE v$mystat.statistic# = v$statname.statistic#

AND v$statname.NAME = 'redo size'

/

 

--7、一致性读取的段及数据块信息

select b.segment_name,a.file#,a.dbarfil,a.dbablk,a.class,a.state

from x$bh a,dba_extents b

where b.RELATIVE_FNO = a.dbarfil

and b.BLOCK_ID <= a.dbablk and b.block_id + b.blocks > a.dbablk

and b.owner='SCOTT' and b.segment_name='EMP'

/

 

--8、等待事件分类及数量

SELECT wait_class#, wait_class_id, wait_class, COUNT (*) AS "count"

FROM v$event_name

GROUP BY wait_class#, wait_class_id, wait_class

ORDER BY wait_class#

/

 

--9、根据sid找到相应的sql语句

SELECT sql_text

FROM v$sqltext a

WHERE a.hash_value = (SELECT sql_hash_value

FROM v$session b

WHERE b.SID = '&sid')

ORDER BY piece ASC

/

 

 

--10、系统自启动以来的累计等待时间前十名

SELECT *

FROM (SELECT event, time_waited

FROM v$system_event

ORDER BY time_waited DESC)

WHERE ROWNUM < 10;

 

--11、查找全表扫描(full scan)及快速全索引扫描(fast full index)

SELECT sql_text

FROM v$sqltext t, v$sql_plan p

WHERE t.hash_value = p.hash_value

AND p.operation = 'TABLE ACCESS'

AND p.options = 'FULL'

ORDER BY p.hash_value, t.piece;

 

SELECT sql_text

FROM v$sqltext t, v$sql_plan p

WHERE t.hash_value = p.hash_value

AND p.operation = 'INDEX'

AND p.options = 'FULL SCAN'

ORDER BY p.hash_value, t.piece;

 

--12、通过具体的等待事件查找到有问题的sql语句(输入参数等待事件如:free buffer waits)

SET linesize 120

COL operation format a55

COL cost format 99999

COL kbytes format 999999

COL object format a25

SELECT hash_value, child_number,

LPAD (' ', 2 * DEPTH)

|| operation

|| ' '

|| options

|| DECODE (ID,

0, SUBSTR (optimizer, 1, 6) || ' Cost=' || TO_CHAR (COST)

) operation,

object_name OBJECT, COST, ROUND (BYTES / 1024) kbytes

FROM v$sql_plan

WHERE hash_value IN (

SELECT a.sql_hash_value

FROM v$session a, v$session_wait b

WHERE a.SID = b.SID

AND b.event = '&waitevent')

ORDER BY hash_value, child_number, ID;

 

--13、查找数据库最繁忙的buffer

SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch

FROM x$bh

ORDER BY tch DESC)

WHERE ROWNUM < 11;

 

--14、查找热点buffer来自哪些对象

SELECT e.owner, e.segment_name, e.segment_type

FROM dba_extents e,

(SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch

FROM x$bh

ORDER BY tch DESC)

WHERE ROWNUM < 11) b

WHERE e.relative_fno = b.dbarfil

AND e.block_id <= b.dbablk

AND e.block_id + e.blocks > b.dbablk;

 

--15、关于latch信息

--主要latch free信息

select * from

(select * from v$latch order by misses desc)

where rownum<11;

--获得session的等待信息

select sid,seq#,event from v$session_wait

--获得具体的子latch信息

SELECT *

FROM (SELECT addr, child#, gets, misses, sleeps, immediate_gets igets,

immediate_misses imiss, spin_gets sgets

FROM v$latch_children

WHERE NAME = 'cache buffers chains'

ORDER BY sleeps DESC)

WHERE ROWNUM < 11;

 

--16、具体热点块的latchbuffer信息及找到相应对象的sql语句

SELECT b.addr, a.ts#, a.dbarfil, a.dbablk, a.tch, b.gets, b.misses, b.sleeps

FROM (SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch, hladdr

FROM x$bh

ORDER BY tch DESC)

WHERE ROWNUM < 11) a,

(SELECT addr, gets, misses, sleeps

FROM v$latch_children

WHERE NAME = 'cache buffers chains') b

WHERE a.hladdr = b.addr

/

 

SELECT distinct e.owner, e.segment_name, e.segment_type

FROM dba_extents e,

(SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch

FROM x$bh

ORDER BY tch DESC)

WHERE ROWNUM < 11) b

WHERE e.relative_fno = b.dbarfil

AND e.block_id <= b.dbablk

AND e.block_id + e.blocks > b.dbablk;

--找引起竞争的相应sql语句

break on hash_value skip 1

SELECT /*+ rule */ hash_value,sql_text

FROM v$sqltext

WHERE (hash_value, address) IN (

SELECT a.hash_value, a.address

FROM v$sqltext a,

(SELECT DISTINCT a.owner, a.segment_name, a.segment_type

FROM dba_extents a,

(SELECT dbarfil, dbablk

FROM (SELECT dbarfil, dbablk

FROM x$bh

ORDER BY tch DESC)

WHERE ROWNUM < 11) b

WHERE a.relative_fno = b.dbarfil

AND a.block_id <= b.dbablk

AND a.block_id + a.blocks > b.dbablk) b

WHERE a.sql_text LIKE '%' || b.segment_name || '%'

AND b.segment_type = 'TABLE')

ORDER BY hash_value, address, piece

/

 

--17、创建临时表保存X$KSMSP的状态

CREATE GLOBAL TEMPORARY TABLE e$ksmsp ON COMMIT PRESERVE ROWS AS

SELECT a.ksmchcom,

SUM (a.CHUNK) CHUNK,

SUM (a.recr) recr,

SUM (a.freeabl) freeabl,

SUM (a.SUM) SUM

FROM (SELECT ksmchcom, COUNT (ksmchcom) CHUNK,

DECODE (ksmchcls, 'recr', SUM (ksmchsiz), NULL) recr,

DECODE (ksmchcls, 'freeabl', SUM (ksmchsiz), NULL) freeabl,

SUM (ksmchsiz) SUM

FROM x$ksmsp GROUP BY ksmchcom, ksmchcls) a

where 1 = 0

GROUP BY a.ksmchcom;

 

--使用创建的临时表保存当前的shared pool的状态

INSERT INTO E$KSMSP

SELECT a.ksmchcom,

SUM (a.CHUNK) CHUNK,

SUM (a.recr) recr,

SUM (a.freeabl) freeabl,

SUM (a.SUM) SUM

FROM (SELECT ksmchcom, COUNT (ksmchcom) CHUNK,

DECODE (ksmchcls, 'recr', SUM (ksmchsiz), NULL) recr,

DECODE (ksmchcls, 'freeabl', SUM (ksmchsiz), NULL) freeabl,

SUM (ksmchsiz) SUM

FROM x$ksmsp

GROUP BY ksmchcom, ksmchcls) a

GROUP BY a.ksmchcom

/

 

--比较前后shared pool内存分配的变化

select a.ksmchcom,a.chunk,a.sum,b.chunk,b.sum,(a.chunk - b.chunk) c_diff,(a.sum -b.sum) s_diff

from

(SELECT a.ksmchcom,

SUM (a.CHUNK) CHUNK,

SUM (a.recr) recr,

SUM (a.freeabl) freeabl,

SUM (a.SUM) SUM

FROM (SELECT ksmchcom, COUNT (ksmchcom) CHUNK,

DECODE (ksmchcls, 'recr', SUM (ksmchsiz), NULL) recr,

DECODE (ksmchcls, 'freeabl', SUM (ksmchsiz), NULL) freeabl,

SUM (ksmchsiz) SUM

FROM x$ksmsp

GROUP BY ksmchcom, ksmchcls) a

GROUP BY a.ksmchcom) a,e$ksmsp b

where a.ksmchcom = b.ksmchcom and (a.chunk - b.chunk) <>0

/

 

--18、找出library cache pin等待的原因

--获得library cache pin等待的对象

select p1raw from v$session_wait where event like 'library%'; --获得等待handle的地址

 

--通过上面获得的地址得到等待的对象

col KGLNAOWN for a10

col KGLNAOBJ for a20

select ADDR,KGLHDADR,KGLHDPAR,KGLNAOWN,KGLNAOBJ,KGLNAHSH,KGLHDOBJ

from X$KGLOB

where KGLHDADR ='&adr'

/

 

--获得持有等待对象的session信息,其中&hdl=(上面获得的handle的地址)

select a.sid,a.username,a.program,b.addr,b.KGLPNADR,b.KGLPNUSE,b.KGLPNSES,b.KGLPNHDL,

b.kGLPNLCK, b.KGLPNMOD, b.KGLPNREQ

from v$session a,x$kglpn b

where a.saddr=b.kglpnuse and b.kglpnhdl = '&hdl' and b.KGLPNMOD<>0

/

 

--上面的语句可以综合到下面的语句具体实现

SELECT addr, kglhdadr, kglhdpar, kglnaown, kglnaobj, kglnahsh, kglhdobj

FROM x$kglob

WHERE kglhdadr IN (SELECT p1raw

FROM v$session_wait

WHERE event LIKE 'library%')

/

 

SELECT a.SID, a.username, a.program, b.addr, b.kglpnadr, b.kglpnuse,

b.kglpnses, b.kglpnhdl, b.kglpnlck, b.kglpnmod, b.kglpnreq

FROM v$session a, x$kglpn b

WHERE a.saddr = b.kglpnuse

AND b.kglpnmod <> 0

AND b.kglpnhdl IN (SELECT p1raw

FROM v$session_wait

WHERE event LIKE 'library%')

/

 

--根据sid信息取得sql信息

SELECT sql_text

FROM v$sqlarea

WHERE (v$sqlarea.address, v$sqlarea.hash_value) IN (

SELECT sql_address, sql_hash_value

FROM v$session

WHERE SID IN (

SELECT SID

FROM v$session a, x$kglpn b

WHERE a.saddr = b.kglpnuse

AND b.kglpnmod <> 0

AND b.kglpnhdl IN (SELECT p1raw

FROM v$session_wait

WHERE event LIKE 'library%')))

/

 

--19、获得参数的描述信息

set linesize 120

col name for a30

col value for a20

col describ for a60

SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ

FROM SYS.x$ksppi x, SYS.x$ksppcv y

WHERE x.inst_id = USERENV ('Instance')

AND y.inst_id = USERENV ('Instance')

AND x.indx = y.indx

AND x.ksppinm LIKE '%&par%'

/

 

--20oracle收集的buffer cacheshared pool 的建议信息

select id,name,block_size,size_for_estimate sfe,size_factor sf,

estd_physical_read_factor eprf,estd_physical_reads epr

from v$db_cache_advice;

 

select SHARED_POOL_SIZE_FOR_ESTIMATE SPSFE,SHARED_POOL_SIZE_FACTOR SPSF,

ESTD_LC_SIZE,ESTD_LC_MEMORY_OBJECTS ELMO,ESTD_LC_TIME_SAVED ELTS,

ESTD_LC_TIME_SAVED_FACTOR ELTSF,ESTD_LC_MEMORY_OBJECT_HITS ELMOH

from v$shared_pool_advice;

 

--21、是 10g 中,决定各参数组件大小的查询

col name for a30

col value for a30

col describ for a50

 

SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ

FROM SYS.x$ksppi x, SYS.x$ksppcv y

WHERE x.inst_id = USERENV ('Instance')

AND y.inst_id = USERENV ('Instance')

AND x.indx = y.indx

AND x.ksppinm like '%pool_size%'

/

 

--22 10g 各动态组件调整时间及调整类型

col component for a30

select COMPONENT,CURRENT_SIZE,MIN_SIZE,LAST_OPER_TYPE,LAST_OPER_MODE,to_char(LAST_OPER_TIME,'yyyy-mm-dd hh24:mi:ss') LOT

from v$sga_dynamic_components;

 

--23sql在工作区中工作方式所占比例

col value for 999999999999

SELECT NAME, VALUE,

100

* ( VALUE

/ DECODE ((SELECT SUM (VALUE) FROM v$sysstat

WHERE NAME LIKE 'workarea executions%'),

0, NULL,

(SELECT SUM (VALUE) FROM v$sysstat

WHERE NAME LIKE 'workarea executions%')

)

) pct

FROM v$sysstat

WHERE NAME LIKE 'workarea executions%'

/

 

--24pga动态性能视图信息

SELECT pga_target_factor factor, low_optimal_size / 1024 low,

ROUND (high_optimal_size / 1024) high,

estd_optimal_executions estd_opt, estd_onepass_executions estd_op,

estd_multipasses_executions estd_mp, estd_total_executions estd_exec

FROM v$pga_target_advice_histogram

WHERE pga_target_factor = 0.25 AND estd_total_executions > 0

/

 

--25、获得存在问题的sql,根据pid

SELECT /*+ ORDERED */

sql_text

FROM v$sqltext a

WHERE (a.hash_value, a.address) IN (

SELECT DECODE (sql_hash_value,

0, prev_hash_value,

sql_hash_value

),

DECODE (sql_hash_value, 0, prev_sql_addr, sql_address)

FROM v$session b

WHERE b.paddr = (SELECT addr

FROM v$process c

WHERE c.spid = '&pid'))

ORDER BY piece ASC

/

 

--26fast_start_mttr_target

select MTTR_TARGET_FOR_ESTIMATE MttrEst,

ADVICE_STATUS AD,

DIRTY_LIMIT DL,

ESTD_CACHE_WRITES ESTCW,

ESTD_CACHE_WRITE_FACTOR EstCWF,ESTD_TOTAL_WRITES ESTW,

ESTD_TOTAL_WRITE_FACTOR ETWF,ESTD_TOTAL_IOS ETIO

from v$mttr_target_advice;

/

 

--27、实例恢复的时间计算

select RECOVERY_ESTIMATED_IOS REIO,

ACTUAL_REDO_BLKS ARB,

TARGET_REDO_BLKS TRB,

LOG_FILE_SIZE_REDO_BLKS LFSRB,

LOG_CHKPT_TIMEOUT_REDO_BLKS LCTRB,

LOG_CHKPT_INTERVAL_REDO_BLKS LCIRB,

FAST_START_IO_TARGET_REDO_BLKS FSIOTRB,

TARGET_MTTR TMTTR,

ESTIMATED_MTTR EMTTR,

CKPT_BLOCK_WRITES CBW

from v$instance_recovery;

 

--而在 10g 中则为,其中writes_autotrne字段指由于自动调整检查点执行的写出次数,而ckpt_block_writes指检查点写出的block数量

SELECT recovery_estimated_ios reios, target_mttr tmttr, estimated_mttr emttr,

writes_mttr wmttr, writes_other_settings woset,

ckpt_block_writes ckptbw, writes_autotune wauto,

writes_full_thread_ckpt wftckpt

FROM v$instance_recovery;

 

--28show_space过程及使用

--普通版本(不适应assm

create or replace procedure show_space ( p_segname in varchar2,

p_owner in varchar2 default user, p_type in varchar2 default 'TABLE' )

as

l_free_blks number;

l_total_blocks number;

l_total_bytes number;

l_unused_blocks number;

l_unused_bytes number;

l_LastUsedExtFileId number;

l_LastUsedExtBlockId number;

l_LAST_USED_BLOCK number;

procedure p( p_label in varchar2, p_num in number ) is

begin

dbms_output.put_line( rpad(p_label,40,'.') || p_num );

end;

begin

dbms_space.free_blocks ( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

freelist_group_id => 0,

free_blks => l_free_blks );

dbms_space.unused_space ( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

total_blocks => l_total_blocks,

total_bytes => l_total_bytes,

unused_blocks => l_unused_blocks,

unused_bytes => l_unused_bytes,

LAST_USED_EXTENT_FILE_ID => l_LastUsedExtFileId,

LAST_USED_EXTENT_BLOCK_ID => l_LastUsedExtBlockId,

LAST_USED_BLOCK => l_LAST_USED_BLOCK );

p( 'Free Blocks', l_free_blks );

p( 'Total Blocks', l_total_blocks );

p( 'Total Bytes', l_total_bytes );

p( 'Unused Blocks', l_unused_blocks );

p( 'Unused Bytes', l_unused_bytes );

p( 'Last Used Ext FileId', l_LastUsedExtFileId );

p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );

p( 'Last Used Block', l_LAST_USED_BLOCK );

end;

 

--完整版本

create or replace procedure show_space

( p_segname_ 1 in varchar2,

p_space in varchar2 default 'MANUAL',

p_type_ 1 in varchar2 default 'TABLE' ,

p_analyzed in varchar2 default 'N',

p_owner_ 1 in varchar2 default user)

as

p_segname varchar2(100);

p_type varchar2(10);

p_owner varchar2(30);

 

l_unformatted_blocks number;

l_unformatted_bytes number;

l_fs1_blocks number;

l_fs1_bytes number;

l_fs2_blocks number;

l_fs2_bytes number;

l_fs3_blocks number;

l_fs3_bytes number;

l_fs4_blocks number;

l_fs4_bytes number;

l_full_blocks number;

l_full_bytes number;

 

l_free_blks number;

l_total_blocks number;

l_total_bytes number;

l_unused_blocks number;

l_unused_bytes number;

l_LastUsedExtFileId number;

l_LastUsedExtBlockId number;

l_LAST_USED_BLOCK number;

 

procedure p( p_label in varchar2, p_num in number )

is

begin

dbms_output.put_line( rpad(p_label,40,'.') ||

p_num );

end;

begin

p_segname := upper(p_segname_1); -- rainy changed

p_owner := upper(p_owner_1);

p_type := p_type_1;

 

if (p_type_1 = 'i' or p_type_1 = 'I') then --rainy changed

p_type := 'INDEX';

end if;

 

if (p_type_1 = 't' or p_type_1 = 'T') then --rainy changed

p_type := 'TABLE';

end if;

 

if (p_type_1 = 'c' or p_type_1 = 'C') then --rainy changed

p_type := 'CLUSTER';

end if;

 

 

dbms_space.unused_space

( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

total_blocks => l_total_blocks,

total_bytes => l_total_bytes,

unused_blocks => l_unused_blocks,

unused_bytes => l_unused_bytes,

LAST_USED_EXTENT_FILE_ID => l_LastUsedExtFileId,

LAST_USED_EXTENT_BLOCK_ID => l_LastUsedExtBlockId,

LAST_USED_BLOCK => l_LAST_USED_BLOCK );

 

if p_space = 'MANUAL' or (p_space <> 'auto' and p_space <> 'AUTO') then

dbms_space.free_blocks

( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

freelist_group_id => 0,

free_blks => l_free_blks );

 

p( 'Free Blocks', l_free_blks );

end if;

 

p( 'Total Blocks', l_total_blocks );

p( 'Total Bytes', l_total_bytes );

p( 'Unused Blocks', l_unused_blocks );

p( 'Unused Bytes', l_unused_bytes );

p( 'Last Used Ext FileId', l_LastUsedExtFileId );

p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );

p( 'Last Used Block', l_LAST_USED_BLOCK );

 

 

/*IF the segment is analyzed */

if p_analyzed = 'Y' then

dbms_space.space_usage(segment_owner => p_owner ,

segment_name => p_segname ,

segment_type => p_type ,

unformatted_blocks => l_unformatted_blocks ,

unformatted_bytes => l_unformatted_bytes,

fs1_blocks => l_fs1_blocks,

fs1_bytes => l_fs1_bytes ,

fs2_blocks => l_fs2_blocks,

fs2_bytes => l_fs2_bytes,

fs3_blocks => l_fs3_blocks ,

fs3_bytes => l_fs3_bytes,

fs4_blocks => l_fs4_blocks,

fs4_bytes => l_fs4_bytes,

full_blocks => l_full_blocks,

full_bytes => l_full_bytes);

dbms_output.put_line(rpad(' ',50,'*'));

dbms_output.put_line('The segment is analyzed');

p( '0% -- 25% free space blocks', l_fs1_blocks);

p( '0% -- 25% free space bytes', l_fs1_bytes);

p( '25% -- 50% free space blocks', l_fs2_blocks);

p( '25% -- 50% free space bytes', l_fs2_bytes);

p( '50% -- 75% free space blocks', l_fs3_blocks);

p( '50% -- 75% free space bytes', l_fs3_bytes);

p( '75% -- 100% free space blocks', l_fs4_blocks);

p( '75% -- 100% free space bytes', l_fs4_bytes);

p( 'Unused Blocks', l_unformatted_blocks );

p( 'Unused Bytes', l_unformatted_bytes );

p( 'Total Blocks', l_full_blocks);

p( 'Total bytes', l_full_bytes);

 

end if;

 

end;

 

 

ASSM 类型的表

 

SQL> exec show_space('t','auto');

Total Blocks............................512

Total Bytes.............................4194304

Unused Blocks...........................78

Unused Bytes............................638976

Last Used Ext FileId....................9

Last Used Ext BlockId...................25608

Last Used Block.........................50

 

PL/SQL procedure successfully completed.

 

 

ASSM 类型的索引

 

 

SQL> exec show_space('t_index','auto','i');

Total Blocks............................80

Total Bytes.............................655360

Unused Blocks...........................5

Unused Bytes............................40960

Last Used Ext FileId....................9

Last Used Ext BlockId...................25312

Last Used Block.........................3

 

PL/SQL procedure successfully completed.

 

 

analyze 过的segment 可以这样

 

SQL> exec show_space('t','auto','T','Y');

Total Blocks............................512

Total Bytes.............................4194304

Unused Blocks...........................78

Unused Bytes............................638976

Last Used Ext FileId....................9

Last Used Ext BlockId...................25608

Last Used Block.........................50

*************************************************

The segment is analyzed

0% -- 25% free space blocks.............0

0% -- 25% free space bytes..............0

25% -- 50% free space blocks............0

25% -- 50% free space bytes.............0

50% -- 75% free space blocks............0

50% -- 75% free space bytes.............0

75% -- 100% free space blocks...........0

75% -- 100% free space bytes............0

Unused Blocks...........................0

Unused Bytes............................0

Total Blocks............................418

Total bytes.............................3424256

 

PL/SQL procedure successfully completed.

 

 

摘自:关于SHOW_SPACE()工具的用法

 

--29、分析表

analyze table table_name compute statistics for table for all indexes for all indexed columns;

 

Analyze table tablename compute statistics;

Analyze index|cluster indexname estimate statistics;

ANALYZE TABLE tablename COMPUTE STATISTICS

FOR TABLE

FOR ALL [LOCAL] INDEXES

FOR ALL [INDEXED] COLUMNS;

ANALYZE TABLE tablename DELETE STATISTICS

ANALYZE TABLE tablename VALIDATE REF UPDATE

ANALYZE TABLE tablename VALIDATE STRUCTURE

[CASCADE]|[INTO TableName]

ANALYZE TABLE tablename LIST CHAINED ROWS [INTO TableName]

等等。

如果想分析整个用户或数据库,还可以采用工具包,可以并行分析

Dbms_utility(8i以前的工具包)

Dbms_stats(8i以后提供的工具包)

dbms_stats.gather_schema_stats(User,estimate_percent=>100,cascade=> TRUE);

dbms_stats.gather_table_stats(User,TableName,degree => 4,cascade => true);

这是对命令与工具包的一些总结

1、对于分区表,建议使用DBMS_STATS,而不是使用Analyze语句。

a) 可以并行进行,对多个用户,多个Table

b) 可以得到整个分区表的数据和单个分区的数据。

c) 可以在不同级别上Compute Statistics:单个分区,子分区,全表,所有分区

d) 可以倒出统计信息

e) 可以用户自动收集统计信息

2DBMS_STATS的缺点

a) 不能Validate Structure

b) 不能收集CHAINED ROWS, 不能收集CLUSTER TABLE的信息,这两个仍旧需要使用Analyze语句。

c) DBMS_STATS 默认不对索引进行Analyze,因为默认CascadeFalse,需要手工指定为True

3、对于oracle 9里面的External TableAnalyze不能使用,只能使用DBMS_STATS来收集信息

 

--30unix环境快速shutdown数据库之前先删除各个进程

$ ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCAL=NO|awk '{print $2}'|xargs kill

然后你再shutdown immediate就很快的了。

 

 

 

第三章监控Oracle数据库的常用shell脚本

2007 11 15 星期四 16:08

这篇文章介绍了DBA每天在监控Oracle数据库方面的职责,讲述了如何通过shell脚本来完成这些重复的监控工作。本文首先回顾了一些DBA常用的Unix命令,以及解释了如何通过Unix Cron来定时执行DBA脚本。同时文章还介绍了8个重要的脚本来监控Oracle数据库:

 

    检查实例的可用性

   

    检查监听器的可用性

 

    检查alert日志文件中的错误信息

   

    在存放log文件的地方满以前清空旧的log文件

 

    分析tableindex以获得更好的性能

 

    检查表空间的使用情况

 

    找出无效的对象

 

    监控用户和事务

 

    DBA需要的Unix基本知识

 

    基本的UNIX命令

 

    以下是一些常用的Unix命令:

 

    ps--显示进程

    grep--搜索文件中的某种文本模式

    mailx--读取或者发送mail

    cat--连接文件或者显示它们

    cut--选择显示的列

    awk--模式匹配语言

    df--显示剩余的磁盘空间

 

    以下是DBA如何使用这些命令的一些例子:

 

    显示服务器上的可用实例:

 

    $ ps -ef | grep smon

    oracle 21832 1 0 Feb 24 ? 19:05 ora_smon_oradb1

    oracle 898 1 0 Feb 15 ? 0:00 ora_smon_oradb2

    dliu 25199 19038 0 10:48: 57 pts /6 0:00 grep smon

    oracle 27798 1 0 05:43:54 ? 0:00 ora_smon_oradb3

    oracle 28781 1 0 Mar 03 ? 0:01 ora_smon_oradb4

 

    显示服务器上的可用监听器:

 

    $ ps -ef | grep listener | grep -v grep

    (译者注:grep命令应该加上-i参数,即grep -i listener,该参数的作用是忽略大小写,因为有些时候listener是大写的,这时就会看不到结果)

    oracle 23879 1 0 Feb 24 ? 33:36 / 8.1.7 /bin/tnslsnr listener_db1 -inherit

    oracle 27939 1 0 05:44:02 ? 0:00 / 8.1.7 /bin/tnslsnr listener_db2 -inherit

    oracle 23536 1 0 Feb 12 ? 4:19 / 8.1.7 /bin/tnslsnr listener_db3 -inherit

    oracle 28891 1 0 Mar 03 ? 0:01 / 8.1.7 /bin/tnslsnr listener_db4 -inherit

 

    查看Oracle存档目录的文件系统使用情况

 

    $ df -k | grep oraarch

    /dev/vx/dsk/proddg/oraarch 71123968 4754872 65850768 7% /u09/oraarch

 

    统计alter.log文件中的行数:

 

    $ cat alert.log | wc -l

    2984   

 

    列出alert.log文件中的全部Oracle错误信息:

 

    $ grep ORA- alert.log

    ORA-00600: internal error code, arguments: [kcrrrfswda.1], [], [], [], [], []

    ORA-00600: internal error code, arguments: [1881], [25860496], [25857716], []

 

    CRONTAB基本

 

    一个crontab文件中包含有六个字段:

 

    分钟 0-59

 

    小时 0-23

 

    月中的第几天 1-31

 

    月份 1 - 12

 

    星期几 0 - 6, with 0 = Sunday

 

    Unix命令或者Shell脚本

 

    要编辑一个crontab文件,输入:

 

    Crontab -e

 

    要查看一个crontab文件,输入:

 

    Crontab -l

    0 4 * * 5 /dba/admin/analyze_table.ksh

    30 3 * * 3,6 /dba/admin/hotbackup.ksh /dev/null 2>&1

 

 

    在上面的例子中,第一行显示了一个分析表的脚本在每个星期5400am运行。第二行显示了一个执行热备份的脚本在每个周三和周六的3 00a .m.运行

 

 

监控数据库的常用Shell脚本

 

    以下提供的8shell脚本覆盖了DBA每日监控工作的90%,你可能还需要修改UNIX的环境变量。

 

    检查Oracle实例的可用性

 

    oratab文件中列出了服务器上的所有数据库

 

    $ cat /var/opt/oracle/oratab

    ###################################################################

    ## /var/opt/oracle/oratab ##

    ###################################################################

    oradb1:/u01/app/oracle/product/ 8.1.7 :Y

    oradb2:/u01/app/oracle/product/ 8.1.7 :Y

    oradb3:/u01/app/oracle/product/ 8.1.7 :N

    oradb4:/u01/app/oracle/product/ 8.1.7 :Y

 

    以下的脚本检查oratab文件中列出的所有数据库,并且找出该数据库的状态(启动还是关闭)

 

################################################

 

    ## ckinstance.ksh ##############################

 

    ORATAB=/var/opt/oracle/oratab

 

    echo "`date` "

 

    echo "Oracle Database(s) Status `hostname` :/n"

 

    db=`egrep -i ":Y|:N" $ORATAB | cut -d":" -f1 | grep -v "/#" | grep -v "/*"`

 

    pslist="`ps -ef | grep pmon`"

 

    for i in $db ; do

 

    echo "$pslist" | grep "ora_pmon_$i" > /dev/null 2>$1

 

    if (( $? )); then

 

    echo "Oracle Instance - $i: Down"

 

    else

 

    echo "Oracle Instance - $i: Up"

 

    fi

 

done

 

 

使用以下的命令来确认该脚本是可以执行的:

 

    $ chmod 744 ckinstance.ksh

    $ ls -l ckinstance.ksh

    -rwxr--r-- 1 oracle dba 657 Mar 5 22:59 ckinstance.ksh*

 

    以下是实例可用性的报表:

 

    $ ckinstance.ksh

    Mon Mar 4 10:44:12 PST 2002

    Oracle Database(s) Status for DBHOST server:

    Oracle Instance - oradb1: Up

    Oracle Instance - oradb2: Up

    Oracle Instance - oradb3: Down

    Oracle Instance - oradb4: Up

 

    检查Oracle监听器的可用性

 

    以下有一个类似的脚本检查Oracle监听器。如果监听器停了,该脚本将会重新启动监听器:

 

#########################################

 

    ## cklsnr.sh ##

 

    #########################################

 

    #!/bin/ksh

 

    DBALIST="primary.dba@company.com,another.dba@company.com";export DBALIST

 

    cd /var/opt/oracle

 

    rm -f lsnr.exist

 

    ps -ef | grep mylsnr | grep -v grep > lsnr.exist

 

    if [ -s lsnr.exist ]

 

    then

 

    echo

 

    else

 

    echo "Alert" | mailx -s "Listener 'mylsnr' on `hostname` is down" $DBALIST

 

    TNS_ADMIN=/var/opt/oracle; export TNS_ADMIN

 

    ORACLE_SID=db1; export ORACLE_SID

 

    ORAENV_ASK=NO; export ORAENV_ASK

 

    PATH=$PATH:/bin:/usr/local/bin; export PATH

 

    . oraenv

 

    LD_LIBRARY_PATH=${ORACLE_HOME}/lib;export LD_LIBRARY_PATH

 

    lsnrctl start mylsnr

 

fi

 

 

检查Alert日志(ORA-XXXXX

 

    每个脚本所使用的一些环境变量可以放到一个profile中:

 

############################################

 

    ## oracle.profile ##

 

    ###############################################

 

    EDITOR=vi;export EDITOR ORACLE_BASE=/u01/app/oracle; export

 

    ORACLE_BASE ORACLE_HOME=$ORACLE_BASE/product/ 8.1.7 ; export

 

    ORACLE_HOME LD_LIBRARY_PATH=$ORACLE_HOME/lib; export

 

    LD_LIBRARY_PATH TNS_ADMIN=/var/opt/oracle;export

 

    TNS_ADMIN NLS_LANG=american; export

 

    NLS_LANG NLS_DATE_FORMAT='Mon DD YYYY HH24:MI:SS'; export

 

    NLS_DATE_FORMAT ORATAB=/var/opt/oracle/oratab;export

 

    ORATAB PATH=$PATH:$ORACLE_HOME:$ORACLE_HOME/bin:

 

    /usr/ccs/bin:/bin:/usr/bin:/usr/sbin:/

 

    sbin:/usr/openwin/bin:/opt/bin:.; export

 

    PATH DBALIST="primary.dba@company.com,

 

   another.dba@company.com";export

 

DBALIST

 

 

以下的脚本首先调用oracle.profile来设置全部的环境变量。如果发现任何的Oracle错误,该脚本还会给DBA发送一个警告的email

 

 

###################################################

 

    ## ckalertlog.sh ##

 

    ####################################################

 

    #!/bin/ksh

 

    .. /etc/oracle.profile

 

    for SID in `cat $ORACLE_HOME/sidlist`

 

    do

 

    cd $ORACLE_BASE/admin/$SID/bdump

 

    if [ -f alert_${SID}.log ]

 

    then

 

    mv alert_${SID}.log alert_work.log

 

    touch alert_${SID}.log

 

    cat alert_work.log >> alert_${SID}.hist

 

    grep ORA- alert_work.log > alert.err

 

    fi

 

    if [ `cat alert.err|wc -l` -gt 0 ]

 

    then

 

    mailx -s "${SID} ORACLE ALERT ERRORS" $DBALIST < alert.err

 

    fi

 

    rm -f alert.err

 

    rm -f alert_work.log

 

done

 

 

清除旧的归档文件

 

    以下的脚本将会在log文件达到90%容量的时候清空旧的归档文件:

 

    $ df -k | grep arch

    Filesystem kbytes used avail capacity Mounted on

    /dev/vx/dsk/proddg/archive 71123968 30210248 40594232 43% /u08/archive

 

#######################################################

 

    ## clean_arch.ksh ##

 

    ########################################################

 

    #!/bin/ksh

 

    df -k | grep arch > dfk.result

 

    archive_filesystem=`awk -F" " '{ print $6 }' dfk.result`

 

    archive_capacity=`awk -F" " '{ print $5 }' dfk.result`

 

 

    if [[ $archive_capacity > 90% ]]

 

    then

 

    echo "Filesystem ${archive_filesystem} is ${archive_capacity} filled"

 

    # try one of the following option depend on your need

 

    find $archive_filesystem -type f -mtime +2 -exec rm -r {} /;

 

    tar

 

    rman

 

fi

 

 

分析表和索引(以得到更好的性能)

 

    以下我将展示如果传送参数到一个脚本中:

 

##########################################################

 

    ## analyze_table.sh ##

 

    ########################################################

 

    #!/bin/ksh

 

    # input parameter: 1: password # 2: SID

 

    if (($#<1)) then echo "Please enter 'oracle' user password as the first parameter !" exit 0

 

    fi

 

    if (($#<2)) then echo "Please enter instance name as the second parameter!" exit 0

 

fi

 

 

要传入参数以执行该脚本,输入:

 

    $ analyze_table.sh manager oradb1

 

    脚本的第一部分产生了一个analyze.sql文件,里面包含了分析表用的语句。脚本的第二部分分析全部的表:

 

###########################################################

 

    ## analyze_table.sh ##

 

    #########################################################

 

    sqlplus -s < oracle/$1@$2

 

    set heading off

 

    set feed off

 

    set pagesize 200

 

    set linesize 100

 

    spool analyze_table.sql

 

    select 'ANALYZE TABLE ' || owner || '.' || segment_name ||

 

    ' ESTIMATE STATISTICS SAMPLE 10 PERCENT;'

 

    from dba_segments

 

    where segment_type = 'TABLE'

 

    and owner not in ('SYS', 'SYSTEM');

 

    spool off

 

    exit

 

    !

 

    sqlplus -s < oracle/$1@$2

 

    @./analyze_table.sql

 

    exit

 

!

 

 

以下是analyze.sql的一个例子:

 

    $ cat analyze.sql

    ANALYZE TABLE HIRWIN.JANUSAGE_SUMMARY ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE HIRWIN.JANUSER_PROFILE ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE APPSSYS.HIST_SYSTEM_ACTIVITY ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE HTOMEH.QUEST_IM_VERSION ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE JSTENZEL.HIST_SYS_ACT_0615 ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE JSTENZEL.HISTORY_SYSTEM_0614 ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE JSTENZEL.CALC_SUMMARY3 ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE IMON.QUEST_IM_LOCK_TREE ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE APPSSYS.HIST_USAGE_SUMMARY ESTIMATE STATISTICS SAMPLE 10 PERCENT;

    ANALYZE TABLE PATROL.P$LOCKCONFLICTTX ESTIMATE STATISTICS SAMPLE 10 PERCENT;

 

 

    检查表空间的使用

 

    以下的脚本检测表空间的使用。如果表空间只剩下10%,它将会发送一个警告email

 

####################################################

 

    ## ck_tbsp.sh ##

 

    ##############################################

 

    #!/bin/ksh

 

    sqlplus -s < oracle/$1@$2

 

    set feed off

 

    set linesize 100

 

    set pagesize 200

 

    spool tablespace.alert

 

    SELECT F.TABLESPACE_NAME,

 

    TO_CHAR ((T.TOTAL_SPACE - F.FREE_SPACE),'999,999') "USED (MB)",

 

    TO_CHAR (F.FREE_SPACE, '999,999') "FREE (MB)",

 

    TO_CHAR (T.TOTAL_SPACE, '999,999') "TOTAL (MB)",

 

    TO_CHAR ((ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)),'999')

 

   ||' %' PER_FREE

 

    FROM (

 

    SELECT TABLESPACE_NAME,

 

    ROUND (SUM (BLOCKS*(SELECT VALUE/1024

 

    FROM V/$PARAMETER

 

    WHERE NAME = 'db_block_size')/1024)

 

    ) FREE_SPACE

 

    FROM DBA_FREE_SPACE

 

    GROUP BY TABLESPACE_NAME

 

    ) F,

 

    (

 

    SELECT TABLESPACE_NAME,

 

    ROUND (SUM (BYTES/1048576)) TOTAL_SPACE

 

    FROM DBA_DATA_FILES

 

    GROUP BY TABLESPACE_NAME

 

    ) T

 

    WHERE F.TABLESPACE_NAME = T.TABLESPACE_NAME

 

    AND (ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)) < 10;

 

    spool off

 

    exit

 

    !

 

    if [ `cat tablespace.alert|wc -l` -gt 0 ]

 

    then

 

    cat tablespace.alert -l tablespace.alert > tablespace.tmp

 

    mailx -s "TABLESPACE ALERT for ${2}" $DBALIST < tablespace.tmp

 

fi

 

 

警告email输出的例子如下:

 

    TABLESPACE_NAME USED (MB) FREE (MB) TOTAL (MB) PER_FREE

    ------------------- --------- ----------- ------------------- ------------------

    SYSTEM 2,047 203 2,250 9 %

    STBS01 302 25 327 8 %

    STBS02 241 11 252 4 %

    STBS03 233 19 252 8 %

 

    查找出无效的数据库对象

 

    以下查找出无效的数据库对象:

 

#################################################

 

    ## ck_tbsp.sh ##

 

    #################################################

 

    #!/bin/ksh

 

    sqlplus -s < oracle/$1@$2

 

    set feed off

 

    set linesize 100

 

    set pagesize 200

 

    spool tablespace.alert

 

    SELECT F.TABLESPACE_NAME,

 

    TO_CHAR ((T.TOTAL_SPACE - F.FREE_SPACE),'999,999') "USED (MB)",

 

    TO_CHAR (F.FREE_SPACE, '999,999') "FREE (MB)",

 

    TO_CHAR (T.TOTAL_SPACE, '999,999') "TOTAL (MB)",

 

    TO_CHAR ((ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)),'999')||' %' PER_FREE

 

    FROM (

 

    SELECT TABLESPACE_NAME,

 

    ROUND (SUM (BLOCKS*(SELECT VALUE/1024

 

    FROM V/$PARAMETER

 

    WHERE NAME = 'db_block_size')/1024)

 

    ) FREE_SPACE

 

    FROM DBA_FREE_SPACE

 

    GROUP BY TABLESPACE_NAME

 

    ) F,

 

    (

 

    SELECT TABLESPACE_NAME,

 

    ROUND (SUM (BYTES/1048576)) TOTAL_SPACE

 

    FROM DBA_DATA_FILES

 

    GROUP BY TABLESPACE_NAME

 

    ) T

 

    WHERE F.TABLESPACE_NAME = T.TABLESPACE_NAME

 

    AND (ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)) < 10;

 

    spool off

 

    exit

 

    !

 

    if [ `cat tablespace.alert|wc -l` -gt 0 ]

 

    then

 

    cat tablespace.alert -l tablespace.alert > tablespace.tmp

 

    mailx -s "TABLESPACE ALERT for ${2}" $DBALIST < tablespace.tmp

 

fi

 

 

监视用户和事务(死锁等)

 

    以下的脚本在死锁发生的时候发送一个警告e-mail

 

########################################################

 

    ## deadlock_alert.sh ##

 

    ######################################################

 

    #!/bin/ksh

 

    .. /etc/oracle.profile

 

    sqlplus -s < oracle/$1@$2

 

    set feed off

 

    set heading off

 

    spool deadlock.alert

 

    SELECT SID, DECODE(BLOCK, 0, 'NO', 'YES' ) BLOCKER,

 

    DECODE(REQUEST, 0, 'NO','YES' ) WAITER

 

    FROM V$LOCK

 

    WHERE REQUEST > 0 OR BLOCK > 0

 

    ORDER BY block DESC;

 

    spool off

 

    exit

 

    !

 

    if [ `cat deadlock.alert|wc -l` -gt 0 ]

 

    then

 

    mailx -s "DEADLOCK ALERT for ${2}" $DBALIST < deadlock.alert

 

fi

 

 

结论

 

    0,20,40 7-17 * * 1-5 /dba/scripts/ckinstance.sh > /dev/null 2>&1

    0,20,40 7-17 * * 1-5 /dba/scripts/cklsnr.sh > /dev/null 2>&1

    0,20,40 7-17 * * 1-5 /dba/scripts/ckalertlog.sh > /dev/null 2>&1

    30 * * * 0-6 /dba/scripts/clean_arch.sh > /dev/null 2>&1

    * 5 * * 1,3 /dba/scripts/analyze_table.sh > /dev/null 2>&1

    * 5 * * 0-6 /dba/scripts/ck_tbsp.sh > /dev/null 2>&1

    * 5 * * 0-6 /dba/scripts/invalid_object_alert.sh > /dev/null 2>&1

    0,20,40 7-17 * * 1-5 /dba/scripts/deadlock_alert.sh > /dev/null 2>&1

 

通过以上的脚本,可大大减轻你的工作。你可以使用这些是来做更重要的工作,例如性能调整。

 

http://hi.baidu.com/mymv/blog/item/2976b4455e8aa427cffca3b3.html

 

解决SQL语句过度消耗CPU问题

问题描述:

     现场工程师报告OSS应用系统运行缓慢,具体操作是通过OSS系统查询话单,很长时间才能返回结果,严重影响了客户的正常使用。

问题处理:

1.登陆数据库主机,用sar命令看到idle的值持续为0CPU的资源已经耗尽:

bz_db1# sar 2 4

SunOS kest 5.8 Generic_108528-19 sun4u     10/26/04

10:56:46     %usr     %sys     %wio    %idle

10:56:48        1        4       95        0

10:56:50        1        5       94        0

10:56:52        0        6       93        0

10:56:54        1        6       93        0

Average         1        5       94       0

 

2.使用TOP命令看到有两个明显占用CPU利用率过高的进程,以下是top命令的结果:

bz_db1# top

last pid:   1664;load averages:   3.26,   3.24,   3.69                       

159 processes: 152 sleeping, 2 running, 2 zombie, 1 stopped, 2 on cpu

CPU states:   1.5% idle, 72.5% user, 17.9% kernel,   8.0% iowait,   0.0% swap

Memory: 2.0G real, 233M free, 2.0G swap in use, 3.4G swap free

    PID USERNAME THR PR NCE   SIZE    RES STATE     TIME FLTS     CPU COMMAND

27420 oracle      1 10    0   1.3G    1.2G cpu01   22.9H     2 31.94% oracle

27418 oracle      1 10    0   1.3G    1.2G run     23.0H     6 26.86% oracle

   5943 oracle      1 59    0   1.3G    1.2G sleep   25:26    37   4.92% oracle

   6295 oracle      1 55    0   1.3G    1.2G run     25:14    74   4.90% oracle

   7778 oracle      1 43    0   1.3G    1.2G sleep   11:43   110   4.86% oracle

13270 oracle      1 59    0   1.3G    1.2G sleep 210.6H     0   0.96% oracle

13056 oracle      1 48    0   1.3G    1.2G sleep 303:30     0   0.37% oracle

10653 root        1 58    0 2560K 1624K cpu00    0:00     0   0.32% top

18827 oracle      1 58    0   1.3G    1.2G sleep   18.4H     0   0.31% oracle

12748 oracle    258 58    0   1.3G    1.2G sleep 555:14     0   0.21% oracle

10634 oracle      1 59    0   1.3G    1.2G sleep    0:01     0   0.21% oracle

28458 oracle      1 58    0   1.3G    1.2G sleep 535:02     0   0.18% oracle

13075 oracle      1 59    0   1.3G    1.2G sleep 326:33     0   0.15% oracle

13173 oracle      1 58    0   1.3G    1.2G sleep 593:07     0   0.13% oracle

   4927 oracle      1 59    0   1.3G    1.2G sleep   33.4H     0   0.11% oracle

可以看到这两个进程号分别是2742027418.

3.捕获占用CPU利用率过高的SQL语句:

以下用到了我总结的SQL语句:

SQL>set line 240

SQL>set verify off

SQL>column sid format 999

SQL>column pid format 999

SQL>column S_# format 999

SQL>column username format A9 heading "ORA User"

SQL>column program   format a29

SQL>column SQL format a60

SQL>COLUMN OSname format a9 Heading "OS User"

SQL>SELECT P.pid pid,S.sid sid,P.spid spid,S.username username,

S.osuser osname,P.serial# S_#,P.terminal,P.program   program,

P.background,S.status,RTRIM(SUBSTR(a.sql_text, 1, 80))   SQL

FROM v$process P, v$session S,v$sqlarea A WHERE P.addr = s.paddr

AND S.sql_address = a.address (+)   AND P.spid LIKE '%&1%';

Enter value for 1: 27420(注意这里应输入占用CPU最高的进程对应的PID

得到以下SQL语句:

Select nvl(sum(LOCALCHARGE),0),nvl(sum(usage),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20041016

and LOCALCHARGE>0 and caller like '0543886%';

27418进程对应的SQL语句如下:

select nvl(sum(LOCALCHARGE),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20041016 and caller like '0543888%';

 

4.使用相关用户连接到数据库,检查其执行计划:

SQL>connect wacos/oss

Connected.

SQL>@?/rdbms/admin/utlxplan.sql

Table created.

SQL>set autotrace on

SQL>set timing on

SQL>Select nvl(sum(LOCALCHARGE),0),nvl(sum(usage),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20041016

and LOCALCHARGE>0 and caller like '0543886%';

NVL(SUM(LOCALCHARGE),0) NVL(SUM(USAGE),0)

----------------------- -----------------

                       0                  0

Elapsed: 00:02:56.37

Execution Plan

----------------------------------------------------------

    0       SELECT STATEMENT Optimizer=CHOOSE (Cost=13435 Card=1 Bytes=5

           3)

    1     0    SORT (AGGREGATE)

    2     1      PARTITION RANGE (ALL)

    3     2        TABLE ACCESS (FULL) OF 'LOCALUSAGE' (Cost=13435 Card=1

           81 Bytes=9593)

Statistics

----------------------------------------------------------

         258   recursive calls

           0   db block gets

       88739   consistent gets

       15705   physical reads

           0   redo size

         580   bytes sent via SQL*Net to client

         651   bytes received via SQL*Net from client

           2   SQL*Net roundtrips to/from client

           8   sorts (memory)

           0   sorts (disk)

           1   rows processed

发现对localusage表做了全表扫描,什么记录也没有返回居然用了2分多钟。

SQL> select nvl(sum(LOCALCHARGE),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20040816 and caller like '0543888%';

NVL(SUM(LOCALCHARGE),0)

-----------------------

                    27.6

Elapsed: 00:03:56.46

Execution Plan

----------------------------------------------------------

    0       SELECT STATEMENT Optimizer=CHOOSE (Cost=13435 Card=1 Bytes=4

           0)

    1     0    SORT (AGGREGATE)

    2     1      PARTITION RANGE (ALL)

    3     2        TABLE ACCESS (FULL) OF 'LOCALUSAGE' (Cost=13435 Card=3

           615 Bytes=144600)

Statistics

----------------------------------------------------------

           0   recursive calls

           0   db block gets

       88588   consistent gets

       15615   physical reads

           0   redo size

         507   bytes sent via SQL*Net to client

         651   bytes received via SQL*Net from client

           2   SQL*Net roundtrips to/from client

           0   sorts (memory)

           0   sorts (disk)

           1   rows processed

这个SQL语句有结果返回,发现也是对localusage表做了全表扫描,但速度也很慢,用了3分多钟。

SQL> select count(*) from localusage;

   COUNT(*)

----------

    5793776

该表有579万多条记录,数据量很大,全表扫描已经不再适合。

5.检查该表的类型:

SQL> SELECT INDEX_NAME, TABLE_NAME, STATUS, PARTITIONED FROM USER_INDEXES WHERE TABLE_NAME='LOCALUSAGE';

INDEX_NAME                      TABLE_NAME                      STATUS    PAR

------------------------------ ------------------------------ -------- ---

I_LOCALUSAGE_SID                LOCALUSAGE                      N/A       YES

UI_LOCALUSAGE_ST_SEQ            LOCALUSAGE                      N/A       YES

SQL> SELECT index_name,table_name,locality FROM user_part_indexes where table_name='LOCALUSAGE';

INDEX_NAME                      TABLE_NAME                      LOCALI

------------------------------ ------------------------------ ------

I_LOCALUSAGE_SID                LOCALUSAGE                      LOCAL

UI_LOCALUSAGE_ST_SEQ            LOCALUSAGE                      LOCAL

发现该表是分区表,并在SERVICEID,STARTIMECDRSEQUENCE列上建立了分区索引,索引类型是local索引。

6.查看分区索引的索引键值:

SQL> select INDEX_NAME,COLUMN_NAME,INDEX_OWNER from dba_ind_columns where TABLE_NAME='LOCALUSAGE';

INDEX_NAME            COLUMN_NAME           INDEX_OWNER

-------------------- -------------------- ------------------------------

I_LOCALUSAGE_SID      SERVICEID             WACOS

UI_LOCALUSAGE_ST_SEQ STARTTIME             WACOS

UI_LOCALUSAGE_ST_SEQ CDRSEQUENCE           WACOS

发现在endtimecaller列上都没有建立索引,这也是导致SQL语句做全表扫描的最终原因。

7.决定创建新的分区索引以消除全表扫描:

(1).首先查看localusage表分区情况:

SQL> select PARTITION_NAME,tablespace_name from user_tab_partitions where table_name='LOCALUSAGE';

PARTITION_NAME                  TABLESPACE_NAME

------------------------------ ------------------------------

LOCALUSAGE_200312               WACOS

LOCALUSAGE_200401               WACOS

LOCALUSAGE_200402               WACOS

LOCALUSAGE_200404               WACOS

LOCALUSAGE_200405               WACOS

LOCALUSAGE_200406               WACOS

LOCALUSAGE_200407               WACOS

LOCALUSAGE_200409               WACOS

LOCALUSAGE_200410               WACOS

LOCALUSAGE_200411               WACOS

LOCALUSAGE_200403               WACOS

LOCALUSAGE_200408               WACOS

LOCALUSAGE_200412               WACOS

13 rows selected.

(2).caller列上创建local分区索引:

SQL>set timing on

SQL>create index I_LOCALUSAGE_CALLER on localusage(caller)

LOCAL

(      

         PARTITION LOCALUSAGE_200312,

PARTITION LOCALUSAGE_200401,

PARTITION LOCALUSAGE_200402,

PARTITION LOCALUSAGE_200404,

PARTITION LOCALUSAGE_200405,

PARTITION LOCALUSAGE_200406,

PARTITION LOCALUSAGE_200407,

PARTITION LOCALUSAGE_200409,

PARTITION LOCALUSAGE_200410,

PARTITION LOCALUSAGE_200411,

PARTITION LOCALUSAGE_200403,

PARTITION LOCALUSAGE_200408,

PARTITION LOCALUSAGE_200412

)

TABLESPACE wacos

STORAGE(

INITIAL 6553600

NEXT 6553600

MAXEXTENTS unlimited

PCTINCREASE 0)

PCTFREE 5

NOLOGGING;

Index created.

Elapsed: 00:06:27.90   (由于数据量比较大,耗时6分钟)

8.再次查看执行计划:

SQL>Select nvl(sum(LOCALCHARGE),0),nvl(sum(usage),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20041016

and LOCALCHARGE>0   and caller like '0543886%';

NVL(SUM(LOCALCHARGE),0) NVL(SUM(USAGE),0)

----------------------- -----------------

                       0                  0

Elapsed: 00:00:03.00

Execution Plan

----------------------------------------------------------

    0       SELECT STATEMENT Optimizer=CHOOSE (Cost=22 Card=1 Bytes=53)

    1     0    SORT (AGGREGATE)

    2     1      PARTITION RANGE (ALL)

    3     2        TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'LOCALUSAGE' (Cost=22 Card=181 Bytes=9593)

    4     3          INDEX (RANGE SCAN) OF 'I_LOCALUSAGE_CALLER' (NON-UNIQUE) (Cost=14 Card=65063)

Statistics

----------------------------------------------------------

           0   recursive calls

           0   db block gets

       16813   consistent gets

         569   physical reads

           0   redo size

         580   bytes sent via SQL*Net to client

         651   bytes received via SQL*Net from client

           2   SQL*Net roundtrips to/from client

           0   sorts (memory)

           0   sorts (disk)

           1   rows processed

这次走了索引后速度明显快多了,用了3秒钟就返回了结果。

SQL>select nvl(sum(LOCALCHARGE),0) from LOCALUSAGE where to_char(ENDTIME,'YYYYMMDD')=20040816 and caller like '0543888%';

NVL(SUM(LOCALCHARGE),0)

-----------------------

                    27.6

Elapsed: 00:00:24.73

Execution Plan

----------------------------------------------------------

    0       SELECT STATEMENT Optimizer=CHOOSE (Cost=22 Card=1 Bytes=40)

    1     0    SORT (AGGREGATE)

    2     1      PARTITION RANGE (ALL)

    3     2        TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'LOCALUSAGE' (Cost=22 Card=3615 Bytes=144600)

    4     3          INDEX (RANGE SCAN) OF 'I_LOCALUSAGE_CALLER' (NON-UNIQUE) (Cost=14 Card=65063)

Statistics

----------------------------------------------------------

           0   recursive calls

           0   db block gets

      129336   consistent gets

        7241   physical reads

           0   redo size

         507   bytes sent via SQL*Net to client

         651   bytes received via SQL*Net from client

           2   SQL*Net roundtrips to/from client

           0   sorts (memory)

           0   sorts (disk)

           1   rows processed

这个SQL语句走了索引,用了24秒钟返回结果,性能明显提高了很多.

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值