|
|
在Oracle数据库中,管理tablespaces通常很难实现从SQL查询得到数据的可视化。一种实现tablespaces可视化且更加容易管理的方法是建立类似于碎片重组功能(defragmentation utilities)的分段使用映射(block usage maps)。 不需要任何图表或者图形功能,你可以使用简单的由Oracelmodplsql包产生的HTML,而modplsql包可在安装Oracle8i和9i时安装。 这其中也包含着风险,因为这一程序必须由一个DBA帐号来运行,所以DBA帐号必须将使用权限赋予每一个操作计划,而操作计划必须包含在wdbsvr.app文件中。为了保护这一文件,你必须确保这一文件只能被Oracle用户和DBA组查阅。如果你愿意把这一程序编写成一个JSP页或者servlet,你也应该非常小心,以防止外部能够使用DBA帐号。 DBA视不能在一个PL/SQL查询,所以你必须将PL/SQL安装为SYS,然后将使用权限分配给允许运行PL/SQL的帐号: connect sys/<password> @blkmap.sql grant execute on blkmap to system; connect system/<password> create synonym blkmap for sys.blkmap; 在这个例子中,我们建立一个名为blkmap包,这一blkmap包具有两个入口点。其中一个是显示tablespaces列表的一个菜单,另一个是实际使用的tablespace分段映射: create or replace package blkma as procedure ts_menu; procedure ts_map(p_name varchar2); end blkmap; / show errors; Tablespace菜单的代码可以是一个与分段映射(block map)页关联的tablespaces列表: procedure ts_menu is begin htp.p('<html>'); htp.p('<body bgcolor="white">'); htp.p('<h2>Tablespaces</h2>'); htp.p('<ul>'); for ts in (select tablespace_name from dba_tablespaces) loop htp.p('<li><a href="blkmap.ts_map?p_id='||ts.tablespace_name||'">' ||ts.tablespace_name||'</a></li>'); end loop; htp.p('</ul>'); htp.p('</body>'); htp.p('</html>'); end ts_menu; 对于tablespace映射,可以生成一个tablespace名称,并请求包含tablespace的每一文件的分段映射。 procedure ts_map(p_name varchar2) is begin page_open; -- open the page htp.p('Tablespace: '||p_name); htp.p('<hr />'); for file in ( select file_id from dba_data_files where tablespace_name = p_name order by file_id ) loop filemap(file.file_id); -- generate a block map for the file htp.p('<hr />'); end loop; info_form; -- generate a form for segment info legend; -- generate a legend for color mappings page_close; -- close the page end ts_map; 对于实际使用的分段映射,我们通常需要显示一个“block”并用颜色表示。使用<table>标签比较复杂。一个更好的方法是生成字符次序,即一段时间之后是间隔,这一间隔允许在任何位置给文本以颜色化。 为了使得分段映射更加有用,我们想列出鼠标位置的block信息,并且突出组成这一片段的block,我们可以使用<a>标签。首先,生成一个指定a和a:hover的类型,然后建立每一Oracle数据库段的类型: <style type="text/css"> a { text-decoration: none; font-family: monospace; font-size: 6pt; } a:hover {background-color: yellow} a.free {background-color: white} a.cache {background-color: #FFCC00} a.cluster {background-color: #9A0000} a.index {background-color: #009900} a.lobindex {background-color: #9AFE66} a.lobsegment {background-color: #9A99FF} a.rollback {background-color: #FF3300} a.temporary {background-color: #DFFEFF} a.table {background-color: #003399} a.other {background-color: magenta} body { background-color: white; font-family: sans-serif; font-size: 10pt; } </style> 我们可以列出有关鼠标位置的block使用者、名称、类型、block数量、以及片段的长度。为了实现这一目的,我们需要两个JavaScript函数,包含以上信息的这两个函数被调用,并传递到表单的域内: <script language="javascript"> function hover(own,nam,typ,bid,len) { document.form.owner.value = own; document.form.name.value = nam; document.form.type.value = typ; document.form.block_id.value = bid; document.form.length.value = len; return true; } function leave() { document.form.owner.value = ""; document.form.name.value = ""; document.form.type.value = ""; document.form.block_id.value = ""; document.form.length.value = ""; return true; } </script> . . . <form name="form"> <table border=0> <tr><td>Owner:</td><td><input name="owner" /></td></tr> <tr><td>Name:</td><td><input name="name" /></td></tr> <tr><td>Type:</td><td><input name="type" /></td></tr> <tr><td>Block#:</td><td><input name="block_id" /></td></tr> <tr><td>Length:</td><td><input name="length" /></td></tr> </table> </form> 对于每一片段,我们需要建立一个block的<a>标签。最后,建立一个显示不同颜色含义的图表: <table border=0> <tr><thcolspan="2">Legend</th></tr> <tr><td><a name="free" class="free">. </a></td> <td>Free Space</td></tr> <tr><td><a name="cache" class="cache">. </a></td> <td>Cache</td></tr> <tr><td><a name="cluster" class="cluster">. </a></td> <td>Cluster</td></tr> <tr><td><a name="index" class="index">. </a></td> <td>Index</td></tr> <tr><td><a name="lobindex" class="lobindex">. </a></td> <td>LobIndex</td></tr> <tr><td><a name="lobsegment" class="lobsegment">. </a></td> <td>LobSegment</td></tr> <tr><td><a name="rollback" class="rollback">. </a></td> <td>Rollback</td></tr> <tr><td><a name="temporary" class="temporary">. </a></td> <td>Temporary</td></tr> <tr><td><a name="table" class="table">. </a></td> <td>Table</td></tr> <tr><td><a name="other" class="other">. </a></td> <td>Other</td></tr> </table> 以下是完整代码: create or replace package blkmap authidcurrent_user as procedure ts_menu; procedure ts_map(p_name varchar2); end blkmap; / show errors; create or replace package body blkmap as procedure page_open; procedure info_form; procedure filemap(p_id number); procedure legend; procedure page_close; -- procedure ts_menu is begin htp.p('<html>'); htp.p('<body bgcolor="white">'); htp.p('<h2>Tablespaces</h2>'); htp.p('<ul>'); for ts in (select tablespace_name from dba_tablespaces) loop htp.p('<li><a href="blkmap.ts_map?p_name='||ts.tablespace_name||'">' ||ts.tablespace_name||'</a></li>'); end loop; htp.p('</ul>'); htp.p('</body>'); htp.p('</html>'); end ts_menu; -- procedure ts_map(p_name varchar2) is begin page_open; htp.p('Tablespace: '||p_name); htp.p('<hr />'); for file in ( select file_id from dba_data_files where tablespace_name = p_name order by file_id ) loop filemap(file.file_id); htp.p('<hr />'); end loop; info_form; legend; page_close; end ts_map; -- procedure page_open is begin htp.p('<html>'); htp.p('<head>'); htp.p('<style type="text/css">'); htp.p('a'); htp.p('{'); htp.p(' text-decoration: none;'); htp.p(' font-family: monospace;'); htp.p(' font-size: 6pt;'); htp.p('}'); htp.p('a:hover {background-color: yellow}'); htp.p('a.free {background-color: white}'); htp.p('a.cache {background-color: #FFCC00}'); htp.p('a.cluster {background-color: #9A0000}'); htp.p('a.index {background-color: #009900}'); htp.p('a.lobindex {background-color: #9AFE66}'); htp.p('a.lobsegment {background-color: #9A99FF}'); htp.p('a.rollback {background-color: #FF3300}'); htp.p('a.temporary {background-color: #DFFEFF}'); htp.p('a.table {background-color: #003399}'); htp.p('a.other {background-color: magenta}'); htp.p('body'); htp.p('{'); htp.p(' background-color: white;'); htp.p(' font-family: sans-serif;'); htp.p(' font-size: 10pt;'); htp.p('}'); htp.p('</style>'); htp.p('<script language="javascript">'); htp.p('function hover(own,nam,typ,bid,len)'); htp.p('{'); htp.p(' document.form.owner.value = own;'); htp.p(' document.form.name.value = nam;'); htp.p(' document.form.type.value = typ;'); htp.p(' document.form.block_id.value = bid;'); htp.p(' document.form.length.value = len;'); htp.p(' return true;'); htp.p('}'); htp.p('function leave()'); htp.p('{'); htp.p(' document.form.owner.value = "";'); htp.p(' document.form.name.value = "";'); htp.p(' document.form.type.value = "";'); htp.p(' document.form.block_id.value = "";'); htp.p(' document.form.length.value = "";'); htp.p(' return true;'); htp.p('}'); htp.p('</script>'); htp.p('<title>File Usage Map</title>'); htp.p('</head>'); htp.p('<body>'); htp.p('<blockquote>'); end page_open; -- procedure info_form is begin -- information form htp.p('<form name="form">'); htp.p('<table border=0>'); htp.p('<tr><td>Owner:</td><td><input name="owner" /></td></tr>'); htp.p('<tr><td>Name:</td><td><input name="name" /></td></tr>'); htp.p('<tr><td>Type:</td><td><input name="type" /></td></tr>'); htp.p('<tr><td>Block#:</td><td><input name="block_id" /></td></tr>'); htp.p('<tr><td>Length:</td><td><input name="length" /></td></tr>'); htp.p('</table>'); htp.p('</form>'); end info_form; -- procedure legend is begin -- legend htp.p('<table border=0>'); htp.p('<tr><thcolspan="2">Legend</th></tr>'); htp.p('<tr><td><a name="free" class="free">. </a></td>'); htp.p('<td>Free Space</td></tr>'); htp.p('<tr><td><a name="cache" class="cache">. </a></td>'); htp.p('<td>Cache</td></tr>'); htp.p('<tr><td><a name="cluster" class="cluster">. </a></td>'); htp.p('<td>Cluster</td></tr>'); htp.p('<tr><td><a name="index" class="index">. </a></td>'); htp.p('<td>Index</td></tr>'); htp.p('<tr><td><a name="lobindex" class="lobindex">. </a></td>'); htp.p('<td>LobIndex</td></tr>'); htp.p('<tr><td><a name="lobsegment" class="lobsegment">. </a></td>'); htp.p('<td>LobSegment</td></tr>'); htp.p('<tr><td><a name="rollback" class="rollback">. </a></td>'); htp.p('<td>Rollback</td></tr>'); htp.p('<tr><td><a name="temporary" class="temporary">. </a></td>'); htp.p('<td>Temporary</td></tr>'); htp.p('<tr><td><a name="table" class="table">. </a></td>'); htp.p('<td>Table</td></tr>'); htp.p('<tr><td><a name="other" class="other">. </a></td>'); htp.p('<td>Other</td></tr>'); htp.p('</table>'); end legend; -- procedure page_close is begin htp.p('</blockquote>'); htp.p('</body>'); htp.p('</html>'); end page_close; -- procedure filemap(p_id number) is l_file_name dba_data_files.file_name%type; l_scale integer := 4; l_seg integer; begin select file_name into l_file_name from dba_data_files where file_id = p_id; htp.p('File: '||l_file_name); htp.p('<hr />'); for seg in ( select null owner, null segment_name, null segment_type, 'free' class, block_id, blocks from dba_free_space where file_id = p_id union select owner, segment_name, segment_type, decode(segment_type, 'CACHE','cache', 'CLSUTER','cluster', 'INDEX','index', 'LOBINDEX','lobindex', 'LOBSEGMENT','lobsegment', 'ROLLBACK','rollback', 'TABLE','table','other'), block_id, blocks from dba_extents where file_id = p_id order by 5 ) loop htp.p('<a href="#'||seg.class||'" class="'||seg.class ||'" onmouseover="javascript:hover(''||seg.owner ||'',''||seg.segment_name ||'',''||seg.segment_type ||'','||seg.block_id ||','||seg.blocks ||')" onmouseout="javascript:leave()">'); l_seg := seg.blocks/l_scale; while l_seg > 1000 loop htp.p(lpad(' ',1000,'. ')); l_seg := l_seg - 1000; end loop; htp.p(lpad(' ',ceil(l_seg),'. ')); htp.p('</a>'); end loop; htp.p('<br>'); htp.p('Scale = 1:'||l_scale); end filemap; end blkmap; / show errors;
|
|