Mobile software for S60

我使用的手机软件(适用于Symbian 9.2,S60 V3)我使用的手机软件(适用于Symbian 9.2,S60 V3)

From: http://www.web20share.com/2008/07/my-mobile-software-for-symbian-92-s60-v3.html

前一阵用了一年多的手机又不慎丢失,买了Nokia6120c,用了大概三个月,感觉很不错,和大家分享一下我手机上安装的软件吧。(自带的几个软件包括:QQ等就不说了)

系统管理类

Taskman:通过Taskman你可以查看当前运行程序所消耗的内存,还可以直接切换到某一个程序,可以选择关闭正在运行的程序或者查看他的相关信息。(推荐)

x-plore:Symbian手机的文件管理软件,可通过蓝牙,红外传输文件;可从Zip,Rar, Jar包中提取文件(解压),可以重启手机等等。(推荐)

文件动力:支持双窗口文件管理,方便的快捷键操作,强大的文件管理功能,强大的进程管理功能,内嵌多种强大方便的实用工具等等。

系统辅助工具

Memoryup:内存管理软件

来电通:可以显示来电号码的所在地址,并且提供了一定的统计功能,包括短信,彩信收发统计功能。

应用软件类

Gmail客户端:这个是最爱了,可以时刻方便Gmail,可以实现Gmail所有功能,支持手机快捷键操作,很方便,可以到这里下载:m.google.com/mail

短信存档:可以存档你的短信。

来电过滤:按照你预设的电话号码或字头,来过滤你想接受/拒绝的来电,同时可过滤匿名来电。

mToolBox:一个很不错的手机小工具,包括计算器 ,秒表,随机生成器,定时器,记事便签,手电筒,计数器,双区时钟,单位转换。

我的财务:简单的记录每天的消费情况,功能很简单,记录分类消费情况。

Fring:太强大的手机客户端了,必备的软件,支持Skype, MSN Messenger, ICQ,Google Talk, SIP, Twitter, AIM; Yahoo!

Msn messenger:安装了Fring之后还是安装了这个,主要是因为这个Msn 的界面和PC上的基本一样比Fring界面友好一些。

UCWEB6:个人用了一阵,感觉还不错,UCWEB6.0手机浏览器引入了微缩模式来展示网页,同时保留以前的自动适应屏幕的浏览模式。

Google地图:Google官方提供的手机地图服务。

个人游戏类

3DSudoku:3D数独,不错的益智游戏

GemMagic:魔力宝石是一种简单、趣味性强、节奏快的棋盘。仅需与相邻的宝石调换位置,使3 个或3 个以上的宝石排列成一条直线即可得分。

Sokoban:推箱子游戏,总共有202局,很有挑战性。

头脑风暴2:一个全新独特而有趣的脑力训练游戏,可以去尝试一下。

这些游戏都是在3g.cn下载

目前个人使用的软件就这么多,里面大部分都是免签名的软件,还没有装杀毒软件,听说东方卫士不错,还没试过,体验过的朋友可以分享一下体验,另外如果你使用了什么好的手机软件可以一起来分享一下。软件下载到电脑,然后传到手机中进行安装;)

 

 

About _serial_direct_read

How to bypass buffer cache for full table scans

From: http://sai-oracle.blogspot.com/2007/12/how-to-bypass-buffer-cache-for-full.html
By Saibabu Devabhaktuni

How to reduce impact of full table scans:

Full table scans (FTS) have their place, even on OLTP databases, and they are not evil when used properly. FTS are unavoidable on most DW databases. So apart from popular belief of possible increased response time and increased I/O, is there any impact on the database?

FTS on a large table can effectively pollute the buffer cache by aging out blocks in the buffer cache otherwise needed by other sessions, even though the FTS blocks are placed at LRU end. It will also have increased latch activity (cache buffer chains, cache buffer lru, etc.). It can also create many CR cloned buffers, if there are any blocks for that table already in the cache.

All these problems can be solved by setting one hidden parameter "_serial_direct_read = true" for that session or at the system level. The beauty of this parameter is that once execution plan is generated for any sql with this setting on, same behavior will be exhibited even when it is not set as long as the cursor is not re-parsed.

"_serial_direct_read = true" basically use "direct path reads" for single threaded multi block read operations like FTS. Oracle will first issue fast checkpoint at object level to write all dirty buffers of that object to the disk and perform direct path reads in to the PGA of shadow process.
This will be especially useful for batch jobs.

Oracle introduced event 10379 to do the same for rowid range scans but never really implemented it fully. Of course you can always use parallel query option to achieve the same thing with multiple threads, but you will be consuming additional resources on the system.

00:50:19 SQL> alter session set "_serial_direct_read" = true;
Session altered.

00:50:19 SQL> select avg(id) from test;

00:50:32 SQL> select event, total_waits from v$session_event
00:50:40 2 where sid = (select sid from v$mystat where rownum = 1)
00:50:40 3 and event like '%read%';

EVENT TOTAL_WAITS
------------------------------ -----------
direct path read 124

A4 纸是多大的像素

 转载自:http://www.snboke.com/article.asp?id=352

今天因为要扫描文件都是A4纸大小,扫描出的都是很大的,为了与打印机的比例相符。找了以下资料!

计算方式
一般的分辨率为XX像素/英寸,其中一英寸为25.4毫米。
所以一毫米的像素数就为XX/25.4。现在的工作就是求XX的值了,把XX的值求出来以后,
直接用XX/25.4 * 210就得到A4纸的像素宽了。


A4纸的尺寸是210mm×297mm。
分辨率是72像素/英寸时,A4纸的尺寸的图像的像素是595×842(推荐用这个大小比例)。  
分辨率是150像素/英寸时,A4纸的尺寸的图像的像素是1240×1754。
分辨率是300像素/英寸时,A4纸的尺寸的图像的像素是2479×3508。

选择不同的分辨率图像像素大小也会随之变化。

查找 ora-4031 元凶的办法

转载自:http://space.itpub.net/?uid-13095417-action-viewspace-itemid-217984

From rollingpig

找元凶的更好方法是看 v$open_cursor+V$sqlarea group by SID

CODE:

select /*+ordered use_hash(c s) no_merge(s) no_merge(c) */
sid,sum(sharable_mem)/1024/1024 from
v$open_cursor c , v$sqlarea s
where c.hash_value =s.hash_value
group by c.sid
order by 2 desc
...
...

立刻就可以找出占用大量share pool memory的SID
然后需要的话再select * from v$open_cursor where sid = .. 看到具体语句

From feng_xin

4031的错误大部分是未绑定变量SQL语句引起的。排除bug后,就要从v$sqlarea与v$open_cursor中找出元凶sql语句。

元凶有两种:
1, 未绑定变量并且大量执行的sql, 这种sql就是晶晶模拟出来的现象。可以通过如下SQL语句抓出来。

先找出sql:

CODE:

select count(*), sum(sharable_mem),substr(sql_text,50) from v$sqlarea group by substr(sql_text,50) order by 1,2;

substr取的字符的个数,根据应用进行调整。

然后根据找出的SQL确定是哪个应用执行的

CODE:

select sid,sharable_mem,s.sql_text from v$open_cursor c , v$sqlarea s where c.hash_value =s.hash_value and s.sql_text like 'xxxxxxxx%'


2, 单条SQL需要大量内存空间,如果内存里有空间但是是由很多小空间碎片组成的话,当执行这个占用内存大的单条sql时,由于不能分配空间,而产生4031错误。这种sql一般来说都是够长够复杂的sql. 可以通过如下SQL语句抓出来。

先找出sql

CODE:

select sid,s.sharable_mem,s.sql_text,s.ADDRESS,s.HASH_VALUE from v$open_cursor c , v$sqlarea s where c.hash_value =s.hash_value order by sharable_mem;


通常sql_text不能把sql显示完整,用如下查询找出完整的sql.

CODE:

select a.address,a.hash_value,a.piece,a.sql_text,a.command_type from v$sqltext a,
(select sid,s.sharable_mem,s.sql_text,s.ADDRESS,s.HASH_VALUE from v$open_cursor c , v$sqlarea s where c.hash_value =s.hash_value and s.sharable_mem>xxxxx) b
where a.address=b.address and a.hash_value=b.hash_value
order by 1,2,3;

关于min(), max()函数访问索引的方法

转载自:http://zhyuh.itpub.net/get/334/mix_max_index


Table sbfi_ctry_flow_curve_wheel有大约1500万条记录,运行下面的sql需要4秒钟左右,
developer认为时间太长,想优化。
SQL>select min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel;
developer很奇怪,trade_dt列上建有一个索引,但是执行的时候,oracle总是选择走
primary key,而不选择那个索引。
经检查,发现表sbfi_ctry_flow_curve_wheel的索引情况如下:
SQL> list
  1  select index_name,column_name,column_position from user_ind_columns
  2  where table_name=upper('sbfi_ctry_flow_curve_wheel')
  3  order by 1
  4* ,3
SQL> /
INDEX_NAME                     COLUMN_NAME  COLUMN_POSITION
------------------------------ ------------ ---------------
SBFI_CTRY_FLOW_CURVE_WHEEL_PK  TRADE_DT                   1
SBFI_CTRY_FLOW_CURVE_WHEEL_PK  CTRY_CODE                  2
SBFI_CTRY_FLOW_CURVE_WHEEL_PK  MONTH                      3
TRADE_DT_INDEX                 TRADE_DT                   1
尝试加hint /*+ ndex(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */,让oracle
选择走索引TRADE_DT_INDEX。结果发现运行时间没有缩短,反而从4秒增加到7秒。
SQL> select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt), max(trade_dt) from bfi_ctry_flow_curve_wheel;
MIN(TRADE MAX(TRADE
--------- ---------
01-JAN-01 07-SEP-07
Elapsed: 00:00:06.91
为什么会出现这种情况?我们尝试用TRACE去跟踪执行过程。
==session 1, don't use hint
alter session set timed_statistics=true
/
alter session set max_dump_file_size=unlimited
/
alter session set tracefile_identifier='PRIMARY_KEY'
/
alter session set events '10046 trace name context forever, level 12'
/
select min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel
/
alter session set events '10046 trace name context off'
/
==session 2, use hint
alter session set timed_statistics=true
/
alter session set max_dump_file_size=unlimited
/
alter session set tracefile_identifier='TRADE_DT_INDEX'
/
alter session set events '10046 trace name context forever, level 12'
/
select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt),
max(trade_dt) from sbfi_ctry_flow_curve_wheel
/
alter session set events '10046 trace name context off'
/
两种情况的trace用tkprof分析后,主要部分结果如下:
==session1, don't use hint
**************************************************************
select min(trade_dt), max(trade_dt)
from
 sbfi_ctry_flow_curve_wheel

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.34          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      2.14       3.84      26044      26067          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      2.14       4.18      26044      26067          0           1
Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: 89 
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
7538400   INDEX FAST FULL SCAN SBFI_CTRY_FLOW_CURVE_WHEEL_PK
(object id 35844)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  db file scattered read                       1649        0.14          2.26
  SQL*Net message from client                     2        4.15          4.15
*************************************************************
 
==session2, use hint
*************************************************************
select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt),
  max(trade_dt)
from
 sbfi_ctry_flow_curve_wheel

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      3.21       8.84      19945      19945          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      3.21       8.85      19945      19945          0           1
Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: 89 
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
7538400   INDEX FULL SCAN TRADE_DT_INDEX (object id 35830)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  db file sequential read                     19945        0.05          5.93
  SQL*Net message from client                     2        6.10          6.10 
*********************************************************
对比后主要的不同罗列如下:
走primary key, consistent read,即query值为 26067,fetch时间为3.84秒,访问主键
索引的方法为INDEX FAST FULL SCAN。
走TRADE_DT_INDEX索引,consistent read值为19945, fetch时间为8.84秒,访问索引
TRADE_DT_INDEX的方法为INDEX FULL SCAN。
关于INDEX FAST FULL SCAN,oracle文档中解释如下:
Fast full index scans are an alternative to a full table scan when the index contains all the
columns that are needed for the query, and at least one column in the index key has
the NOT NULL constraint. A fast full scan accesses the data in the index itself, without
accessing the table. It cannot be used to eliminate a sort operation, because the data is
not ordered by the index key. It reads the entire index using multiblock reads, unlike a
full index scan, and can be parallelized.
You can specify fast full index scans with the initialization parameter
OPTIMIZER_FEATURES_ENABLE or the INDEX_FFS hint. Fast full index scans cannot be
performed against bitmap indexes.
A fast full scan is faster than a normal full index scan in that it can use multiblock I/O
and can be parallelized just like a table scan.
关于INDEX FAST FULL SCAN:
A full scan is available if a predicate references one of the columns in the index.
The predicate does not need to be an index driver. A full scan is also available when
there is no predicate, if both the following conditions are met:
All of the columns in the table referenced in the query are included in the index.
At least one of the index columns is not null.
A full scan can be used to eliminate a sort operation, because the data is ordered by the
index key. It reads the blocks singly.
上面明确讲到了fast full scan比full scan要快,因为它用multiblock I/O,而且可以
parallelized。
顺便也注意到要调优的这句sql,只返回trade_dt列的值,满足index (fast) full scan
的条件,即返回结果的列全都包含在索引里,非空。所以该sql只要扫描索引就能返回
需要的结果,不需要再根据rowid去访问表。
既然要扫描整个索引,FAST FULL SCAN 比 FULL SCAN 快,TRADE_DT_INDEX 的 size 
比 PK 的 size 小,那对 RADE_DT_INDEX 做FFS应该是最快的访问路径。用index_ffs
hint:
SQL> select /*+ index_ffs(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */
min(trade_dt), max(trade_dt) from bfi_ctry_flow_curve_wheel;
MIN(TRADE MAX(TRADE
--------- ---------
01-JAN-01 07-SEP-07
Elapsed: 00:00:02.61
相比上面的4秒和7秒是快了一些。
但是根据一般的理解,象min(),max()这样的函数,Oracle应该直接访问索引的最左边或者
最右边,这样的访问速度才是最快的。尝试
SQL>select min(trade_dt) from sbfi_ctry_flow_curve_wheel
并生成10046 trace文件,用tkprof格式化后结果如下:
==session 3, single function
*************************************************************
select max(trade_dt)
from
 sbfi_ctry_flow_curve_wheel

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          0          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        4      0.00       0.00          0          6          0           2
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        8      0.00       0.01          0          6          0           2
Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: 89 
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
      1   INDEX FULL SCAN (MIN/MAX) SBFI_CTRY_FLOW_CURVE_WHEEL_PK
(object id 35844)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       4        0.00          0.00
  SQL*Net message from client                     4      494.34        501.34
*************************************************************
一些重要的信息: consistent read值为6, 相比以前的26067(PK)/19945(index),
fetch时间<0.01秒,相比3.84s(PK)/8.84s(index)。访问索引的方法为
INDEX FULL SCAN (MIN/MAX)。这是oracle文档库里没有提到的访问方法,
但是http://www.juliandyke.com/Optimisation/Operations/IndexFullScanMinMax.html
有一些介绍:Returns the first or last entry in the index。
看来oracle对于单个的min(),max()函数,能直接访问索引的最左边或者最右边取到结果,
但是如果两个函数同时出现在一个sql里,oracle就只能扫描整个索引。这一点上还是
不够智能。

使用进程管理(AppMan)的一点心得

转载,原始出处不明,略有修改

APPMAN 应该来说是 S60 机器必装的软件,我们可以用它来关闭线程。清理程序退出后未释放的运行空间~虽然 N72 的空间已经比较大了,但运行程序多了还是很有必要装的。

一、系统资源的管理  
在功能表中进入 APPMAN 即看见系统资源这一页,按右键刷新就可以看见具体程序信息点左键选项即看见菜单第一个为“压缩内存”,第二选项“工具”中有“关闭全部应用”即可关闭开启的程序(这里说明下~一些开机自启动程序是无法关闭的~比如区号秀之类的,这些要在线程中结束)。“关闭全部应用下面”的重新启动手机可快速无声的重启手机,(再说明下,s60的系统运行了久了,有些内存是无法清理的,必须重新启动手机来清理,似乎symbianware公司无法解决S60系统的此问题才加入了重新启动手机选项,而同属于symbian的UIQ界面系统却可以用Sman的快照功能近乎完美的解决,小小遗憾下)

二、运行
在此界面下可将光标移至想关闭的程序.可在选项选择关闭程序(仍有部分程序不能被关闭.继续看下面的进程页.)
将光标移至程序按右键(进入)可选择进入当前显示的程序.
选项-工具可查看光标上的程序信息.线程信息.选项-设置选项中可选择显示所有在开机后打开的程序.包括系统的.

三、线程
我选择的是不显示ROM程序~毕竟N72内存还是比较大的~没必要关闭系统的。
“线程”选项主要是为了关闭一个开机自运行的程序线程。比如杀毒软件等~“选择”不显示ROM程序“选项可以清楚看到那些是自己装的程序出现的线程。将光标移至线程.可选择关闭(选项-工具-关闭选定程序).[部分系统的线程必须关闭2-3次才可完全关闭].部分顽固程序.也可在此关闭.
这里介绍一些系统线程的具体影响
1  menu 可以关只是你从进 menu 它又会出现;
2  CNTSrv 不能关闭,关了电话会很慢;
3  Sysamob 可以关nokia.;
4  iserverarcese 可以关;
5  emon 可以关;
6  UNIPERTAR 可以关但是当我们进图片时 Unable to open Images! 就是不能进入图片;
7  sdp 可以关;
8  Schexe 不能关闭会出现 App closed Appman.
9  MSexe 可以关但是你要先关 Ncnlist 和 Sysamob,不然.是关不到的;
10 BTServer 可以关   但是开蓝牙BTServer又会被打开啦....
11 CbsServer 可以关;
12 CLKNITZMDLS 可以关 [补充] 这是闹钟的,如果关了进闹钟时要等大该10秒才会进入! 这时 APPMAN 里又会有 CLKNITZMDLS 这个程序了.
13 CalenSvr 可以关;
14 satsvr 可以关;
15 btmanserver 不能关闭会出现“硬”死机 要拆电池了;
16 Ncnlist 可以关但是如果没接到来电,原本会出现1通未接来电.这1通未接来电将不会出现;
17 faxmodem 可以关 faxmodem关了之后...手机就不能通过数据线做猫了;
18 SecurityObserver 可以关 ;
19 WAPSTKSRV 不能关闭会出现 重启
(20 21 在多次转载中都丢失了:()
22 Autolock 可以关 ;
23 ScreenSaver 可以关,关了就没 ScreenSaver 这工能了;
24 watcher 可以关但是会收不到短信息,但可以发短信息.
25 Phone 不能关闭 会出现重启;
26 SysAp 不能关闭 会出现重启;
27 sae 不能关闭 会出现重启;
28 EDbsrv 不能关闭会出现“硬”死机 要拆电池了;
29 Sysage 不能关闭会出现“硬”死机 要拆电池了;
30 PhoneServer 可以关,但是关掉的话进通信纪录会出现系统错误;
31 MediaServerStub 可以关,这是声音,关了你按件盘将不会有声音还有就是每当你看 SM 或 REALONE 退出时会出现 APP closed MediaServerStub!
32 不能关闭 会出现重启;
33 C32exe 不能关闭会出现 App closed Appman;
34 EikSrvs 不能关闭,关了电话会很慢退出时会出现重启
35 randsvr 可以关;
36 EInfoServer 可以关;
37 DosServer 可以关 但是关了将不能关机和电话的灯将不能关,所以是不要关的好 关了就又要拆电池了;
38 SharedDataServer 不能关闭会出现 App closed Appman.
39 Starter 不能关闭会出现 App closed main! 然后会重启;
40 FbServ 不能关闭 会出现重启;
41 EwSrv 不能关闭 会出现重启;
42 EFile 不能关闭会出现 App closed Appman.
43 EKern 不能关闭会出现 App closed Appman.(呼呼,累趴了,支持啊!)

四、文档显示系统中的文档~此选项不常用

五、安装
此选项可以查看你所安装的程序,同样,我也选择了不显示ROM应用。程序按右键即可打开,也可选择将程序添加至捷径中:选项-添加至捷径.(V5版本以上可以添加)
垃圾桶标志为一般为垃圾文件,右键为删除。但APPMAN的识别不一定准确~一些第三方软件的存档文件会被认为为垃圾文件~还有一些游戏的存档也是如此~删除时候须谨慎

oracle9i中全文检索的创建与使用

物化视图日志结构

转载自: http://yangtingkun.itpub.net/post/468/20498

物化视图的快速刷新要求基本必须建立物化视图日志,这篇文章简单描述一下物化视图日志中各个字段的含义和用途。


物化视图日志的名称为MLOG$_后面跟基表的名称,如果表名的长度超过20位,则只取前20位,当截短后出现名称重复时,Oracle会自动在物化视图日志名称后面加上数字作为序号。


物化视图日志在建立时有多种选项:可以指定为ROWID、PRIMARY KEY和OBJECT ID几种类型,同时还可以指定SEQUENCE或明确指定列名。上面这些情况产生的物化视图日志的结构都不相同。


任何物化视图都会包括的列:


SNAPTIME$$:用于表示刷新时间。


DMLTYPE$$:用于表示DML操作类型,I表示INSERT,D表示DELETE,U表示UPDATE。


OLD_NEW$$:用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)表示旧值,U表示UPDATE操作。


CHANGE_VECTOR$$表示修改矢量,用来表示被修改的是哪个或哪几个字段。


如果WITH后面跟了ROWID,则物化视图日志中会包含:


M_ROW$$:用来存储发生变化的记录的ROWID。


如果WITH后面跟了PRIMARY KEY,则物化视图日志中会包含主键列。


如果WITH后面跟了OBJECT ID,则物化视图日志中会包含:


SYS_NC_OID$:用来记录每个变化对象的对象ID。


如果WITH后面跟了SEQUENCE,则物化视图日子中会包含:


SEQUENCE$$:给每个操作一个SEQUENCE号,从而保证刷新时按照顺序进行刷新。


如果WITH后面跟了一个或多个COLUMN名称,则物化视图日志中会包含这些列。

 


下面通过例子进行详细说明:


SQL> create table t_rowid (id number, name varchar2(30), num number);


表已创建。


SQL> create materialized view log on t_rowid with rowid, sequence (name, num) including new values;


实体化视图日志已创建。


SQL> create table t_pk (id number primary key, name varchar2(30), num number);


表已创建。


SQL> create materialized view log on t_pk with primary key;


实体化视图日志已创建。


SQL> create type t_object as object (id number, name varchar2(30), num number);
  2  /


类型已创建。


SQL> create table t_oid of t_object;


表已创建。


SQL> create materialized view log on t_oid with object id;


实体化视图日志已创建。


建立环境后来看看物化视图日志中包含的自动:


SQL> desc mlog$_t_rowid
 名称                                    是否为空? 类型
 --------------------------------------- -------- -------------
 NAME                                             VARCHAR2(30)
 NUM                                              NUMBER
 M_ROW$$                                          VARCHAR2(255)
 SEQUENCE$$                                       NUMBER
 SNAPTIME$$                                       DATE
 DMLTYPE$$                                        VARCHAR2(1)
 OLD_NEW$$                                        VARCHAR2(1)
 CHANGE_VECTOR$$                                  RAW(255)


除了最基本的4列之外,由于指定了ROWID、SEQUENCE和NAME、NUM列,因此物化视图日志中包含了相对应的列。


SQL> desc mlog$_t_pk
 名称                                      是否为空? 类型
 ----------------------------------------- -------- -------------
 ID                                                 NUMBER
 SNAPTIME$$                                         DATE
 DMLTYPE$$                                          VARCHAR2(1)
 OLD_NEW$$                                          VARCHAR2(1)
 CHANGE_VECTOR$$                                    RAW(255)


主键物化视图日志中除了基本列之外还包括基本的主键。


SQL> desc mlog$_t_oid
 名称                                    是否为空? 类型
 --------------------------------------- -------- -------------
 SYS_NC_OID$                                      RAW(16)
 SNAPTIME$$                                       DATE
 DMLTYPE$$                                        VARCHAR2(1)
 OLD_NEW$$                                        VARCHAR2(1)
 CHANGE_VECTOR$$                                  RAW(255)


对象表的物化视图日志建立后包含系统对象标识列。


一、主键列、ROWID列、OBJECT ID列、SEQUENCE列和建立物化视图时指明的列。


主键、ROWID或OBJECT ID用来唯一表示物化视图日志中的记录。


SEQUENCE会根据操作发生的顺序对物化视图日志中的记录编号。


建立物化视图时指明的列会在物化视图日志中进行记录。


SQL> insert into t_rowid values (1, 'a', 5);


已创建 1 行。


SQL> update t_rowid set name = 'c' where id = 1;


已更新 1 行。


SQL> delete t_rowid;


已删除 1 行。


SQL> select name, num, m_row$$, sequence$$, dmltype$$ from mlog$_t_rowid;


NAME              NUM M_ROW$$            SEQUENCE$$ D
---------- ---------- ------------------ ---------- -
a                   5 AAACIDAAFAAAAD4AAA      70019 I
a                   5 AAACIDAAFAAAAD4AAA      70020 U
c                   5 AAACIDAAFAAAAD4AAA      70021 U
c                   5 AAACIDAAFAAAAD4AAA      70022 D


SQL> insert into t_pk values (1, 'a', 5);


已创建 1 行。


SQL> update t_pk set name = 'c' where id = 1;


已更新 1 行。


SQL> delete t_pk;


已删除 1 行。


SQL> select id, dmltype$$ from mlog$_t_pk;


        ID D
---------- -
         1 I
         1 U
         1 D


SQL> insert into t_oid values (1, 'a', 5);


已创建 1 行。


SQL> update t_oid set name = 'c' where id = 1;


已更新 1 行。


SQL> delete t_oid;


已删除 1 行。


SQL> select sys_nc_oid$, dmltype$$ from mlog$_t_oid;


SYS_NC_OID$                      D
-------------------------------- -
9F6DA94248EE40D5AB1E50700F9566EA I
9F6DA94248EE40D5AB1E50700F9566EA U
9F6DA94248EE40D5AB1E50700F9566EA D


SQL> rollback;


回退已完成。


二、时间列


当基本发生DML操作时,会记录到物化视图日志中,这时指定的时间4000年1月1日0时0分0秒。如果物化视图日志供多个物化视图使用,则一个物化视图刷新后会将它刷新的记录的时间更新为它刷新的时间。


下面建立快速刷新的两个物化视图来演示时间列的变化。(只有建立快速刷新的物化视图才能使用物化视图日志,如果只建立一个物化视图,则物化视图刷新完会将物化视图日志清除掉。


SQL> create materialized view mv_t_rowid refresh fast on commit as
  2  select name, count(*) from t_rowid group by name;


实体化视图已创建。


SQL> create materialized view mv_t_rowid1 refresh fast as
  2  select name, count(*) from t_rowid group by name;


实体化视图已创建。


SQL> insert into t_rowid values (1, 'a', 5);


已创建 1 行。


SQL> update t_rowid set name = 'c' where id = 1;


已更新 1 行。


SQL> delete t_rowid;


已删除 1 行。


SQL> select snaptime$$ from mlog$_t_rowid;


SNAPTIME$$
-------------------
4000-01-01 00:00:00
4000-01-01 00:00:00
4000-01-01 00:00:00
4000-01-01 00:00:00


SQL> commit;


提交完成。


SQL> select snaptime$$ from mlog$_t_rowid;


SNAPTIME$$
-------------------
2005-03-05 00:40:32
2005-03-05 00:40:32
2005-03-05 00:40:32
2005-03-05 00:40:32


COMMIT后,物化视图mv_t_rowid刷新,将SNAPTIME$$列更新成自己的刷新时间。

 


三、操作类型和新旧值


操作类型比较简单:只包括I(INSERT)、D(DELETE)和U(UPDATE)三种。


新旧值也包括三种:O表示旧值(一般对应的操作时DELETE)、N表示新值(一般对应的操作是INSERT),还有一种U(对应UPDATE操作)。


SQL> insert into t_pk values (1, 'a', 5);


已创建 1 行。


SQL> insert into t_pk values (2, 'b', 7);


已创建 1 行。


SQL> insert into t_pk values (3, 'c', 9);


已创建 1 行。


SQL> update t_pk set name = 'c' where id = 1;


已更新 1 行。


SQL> update t_pk set id = 4 where id = 2;


已更新 1 行。


SQL> delete t_pk where id = 3;


已删除 1 行。


SQL> select id, dmltype$$, old_new$$ from mlog$_t_pk;


        ID D O
---------- - -
         1 I N
         2 I N
         3 I N
         1 U U
         2 D O
         4 I N
         3 D O


已选择7行。


开始是插入三条记录,接着是UPDATE操作。需要注意,对于基于主键的物化视图日志,如果更新了主键,则UPDATE操作转化为一条DELETE操作,一条INSERT操作。最后是DELETE操作。


SQL> drop materialized view log on t_rowid;


实体化视图日志已删除。


SQL> create materialized view log on t_rowid with rowid, sequence (name, num) including new values;


实体化视图日志已创建。


SQL> insert into t_rowid values (1, 'a', 5);


已创建 1 行。


SQL> insert into t_rowid values (2, 'b', 7);


已创建 1 行。


SQL> insert into t_rowid values (3, 'c', 9);


已创建 1 行。


SQL> update t_rowid set name = 'c' where id = 1;


已更新 1 行。


SQL> update t_rowid set id = 4 where id = 2;


已更新 1 行。


SQL> delete t_rowid where id = 3;


已删除 1 行。


SQL> select name, num, m_row$$, dmltype$$, old_new$$ from mlog$_t_rowid;


NAME              NUM M_ROW$$            D O
---------- ---------- ------------------ - -
a                   5 AAACIDAAFAAAAD4AAC I N
b                   7 AAACIDAAFAAAAD4AAA I N
c                   9 AAACIDAAFAAAAD4AAB I N
a                   5 AAACIDAAFAAAAD4AAC U U
c                   5 AAACIDAAFAAAAD4AAC U N
b                   7 AAACIDAAFAAAAD4AAA U U
b                   7 AAACIDAAFAAAAD4AAA U N
c                   9 AAACIDAAFAAAAD4AAB D O


已选择8行。


查询结果和上面类似,唯一的区别是每条UPDATE操作都对应物化视图日志中的两条记录。一条对应UPDATE操作的原记录DMLTYPE$$和OLD_NEW$$都为U,一条对应UPDATE操作后的新记录,DMLTYPE$$为U,OLD_NEW$$为N。当建立物化视图日志时指出了INCLUDING NEW VALUES语句时,就会出现这种情况。

 


四、修改矢量


最后简单讨论一下CHANGE_VECTOR$$列。


INSERT和DELETE操作都是记录集的,即INSERT和DELETE会影响整条记录。而UPDATE操作是字段集的,UPDATE操作可能会更新整条记录的所有字段,也可能只更新个别字段。


无论从性能上考虑还是从数据的一致性上考虑,物化视图刷新时都应该是基于字段集。Oracle就是通过CHANGE_VECTOR$$列来记录每条记录发生变化的字段包括哪些。


基于主键、ROWID和OBJECT ID的物化视图日志在CHANGE_VECTOR$$上略有不同,但是总体设计的思路是一致的。


CHANGE_VECTOR$$列是RAW类型,其实Oracle采用的方式就是用每个BIT位去映射一个列。


比如:第一列被更新设置为02,即00000010。第二列设置为04,即00000100,第三列设置为08,即00001000。当第一列和第二列同时被更新,则设置为06,00000110。如果三列都被更新,设置为0E,00001110。


依此类推,第4列被更新时为10,第5列20,第6列40,第7列80,第8列0001。当第1000列被更新时,CHANGE_VECTOR$$的长度为1000/4+2为252。


除了可以表示UPDATE的字段,还可以表示INSERT和DELETE。DELETE操作CHANGE_VECTOR$$列为全0,具体个数由基表的列数决定。INSERT操作的最低位为FE如果基表列数较多,而存在高位的话,所有的高位都为FF。如果INSERT操作是前面讨论过的由UPDATE操作更新了主键造成的,则这个INSERT操作对应的CHANGE_VECTOR$$列为全FF。


SQL> insert into t_rowid values (1, 'a', 5);


已创建 1 行。


SQL> insert into t_rowid values (2, 'b', 7);


已创建 1 行。


SQL> insert into t_rowid values (3, 'c', 9);


已创建 1 行。


SQL> update t_rowid set name = 'c' where id = 1;


已更新 1 行。


SQL> update t_rowid set id = 4 where id = 2;


已更新 1 行。


SQL> update t_rowid set name = 'd', num = 11 where id = 3;


已更新 1 行。


SQL> delete t_rowid where id = 3;


已删除 1 行。


SQL> select name, num, m_row$$, dmltype$$, old_new$$, change_vector$$ from mlog$_t_rowid;


NAME                        NUM M_ROW$$            D O CHANGE_VEC
-------------------- ---------- ------------------ - - ----------
a                             5 AAACIgAAFAAAAD4AAA I N FE
b                             7 AAACIgAAFAAAAD4AAB I N FE
c                             9 AAACIgAAFAAAAD4AAC I N FE
a                             5 AAACIgAAFAAAAD4AAA U U 04
c                             5 AAACIgAAFAAAAD4AAA U N 04
b                             7 AAACIgAAFAAAAD4AAB U U 02
b                             7 AAACIgAAFAAAAD4AAB U N 02
c                             9 AAACIgAAFAAAAD4AAC U U 0C
d                            11 AAACIgAAFAAAAD4AAC U N 0C
d                            11 AAACIgAAFAAAAD4AAC D O 00


已选择10行。


可以看到,正如上面分析的,INSERT为FE,DELETE为00,对第一列的更新为02,第二列为04,第二列和第三列都更新为0C。需要注意,正常情况下,第一列会从02开始,但是如果对MLOG$表执行了TRUNCATE操作,或者重建了物化视图日志,则可能造成第一列开始位置发生偏移。


SQL> insert into t_pk values (1, 'a', 5);


已创建 1 行。


SQL> insert into t_pk values (2, 'b', 7);


已创建 1 行。


SQL> insert into t_pk values (3, 'c', 9);


已创建 1 行。


SQL> update t_pk set name = 'c' where id = 1;


已更新 1 行。


SQL> update t_pk set id = 4 where id = 2;


已更新 1 行。


SQL> delete t_pk where id = 1;


已删除 1 行。


SQL> select * from mlog$_t_pk;


        ID SNAPTIME$$          D O CHANGE_VEC
---------- ------------------- - - ----------
         1 4000-01-01 00:00:00 I N FE
         2 4000-01-01 00:00:00 I N FE
         3 4000-01-01 00:00:00 I N FE
         1 4000-01-01 00:00:00 U U 04
         2 4000-01-01 00:00:00 D O 00
         4 4000-01-01 00:00:00 I N FF
         1 4000-01-01 00:00:00 D O 00


已选择7行。


这个结果和ROWID类型基本一致,不同的是,如果更新了主键,会将UPDATE操作在物化视图日志中记录为一条DELETE和一条INSERT,不过这时INSERT对应的CHANGE_VECTOR$$的值是FF。


SQL> insert into t_oid values (1, 'a', 5);


已创建 1 行。


SQL> update t_oid set name = 'c' where id = 1;


已更新 1 行。


SQL> update t_oid set id = 5 where id = 1;


已更新 1 行。


SQL> delete t_oid;


已删除 1 行。


SQL> select * from mlog$_t_oid;


SYS_NC_OID$                      SNAPTIME$$          D O CHANGE_VEC
-------------------------------- ------------------- - - ----------
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 I N FE
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 U U 10
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 U U 08
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 D O 00


SQL> select name, segcollength from sys.col$ where obj# =
  2  (select object_id from user_objects where object_name = 'T_OID');


NAME                 SEGCOLLENGTH
-------------------- ------------
SYS_NC_OID$                    16
SYS_NC_ROWINFO$                 1
ID                             22
NAME                           30
NUM                            22


这个结果也和ROWID类型基本一致,需要注意的是,由于对象表包含两个隐含列,因此ID不再是第一个字段,而是第三个,因此对应的值是08。


SQL> create table t (
  2  col1 number,
  3  col2 number,
  4  col3 number,
  5  col4 number,
  6  col5 number,
  7  col6 number,
  8  col7 number,
  9  col8 number,
 10  col9 number,
 11  col10 number,
 12  col11 number,
 13  col12 number
 14  );


表已创建。


SQL> create materialized view log on t with rowid;


实体化视图日志已创建。


SQL> insert into t values (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);


已创建 1 行。


SQL> update t set col1 = 10;


已更新 1 行。


SQL> update t set col11 = 110;


已更新 1 行。


SQL> update t set col5 = 50, col12 = 120;


已更新 1 行。


SQL> delete t;


已删除 1 行。


SQL> select * from mlog$_t;


M_ROW$$            SNAPTIME$$          D O CHANGE_VEC
------------------ ------------------- - - ----------
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 I N FEFF
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 0200
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 0008
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 2010
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 D O 0000


最后看一个包含列数较多的例子,唯一需要注意的是,低位在左,高位在右。

转载自:http://yangtingkun.itpub.net/post/468/286875

即使将物化视图的约束建立和基表完全一致,由于物化视图的刷新机制(Oracle在刷新物化视图的时候没有保证更新的顺序),也会产生约束冲突的现象。

一个简单的例子:

SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> ALTER TABLE T ADD CONSTRAINT UN_T_NAME UNIQUE (NAME);

表已更改。

SQL> CREATE MATERIALIZED VIEW LOG ON T;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW MV_T REFRESH FAST AS SELECT * FROM T;

实体化视图已创建。

SQL> ALTER TABLE MV_T ADD CONSTRAINT UN_MV_T_NAME UNIQUE (NAME);

表已更改。

SQL> INSERT INTO T VALUES (1, 'A');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, 'B');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')

PL/SQL 过程已成功完成。

上面构造了一个简单的物化视图,物化视图和基表建立了相同的唯一约束。

下面进行一个循环的更新操作,然后观察刷新的情况:

SQL> UPDATE T SET NAME = 'C' WHERE ID = 1;

已更新 1 行。

SQL> UPDATE T SET NAME = 'A' WHERE ID = 2;

已更新 1 行。

SQL> UPDATE T SET NAME = 'B' WHERE ID = 1;

已更新 1 行。

SQL> COMMIT;

提交完成。

SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
BEGIN DBMS_MVIEW.REFRESH('MV_T'); END;

*
ERROR 位于第 1 行:
ORA-12008: 实体化视图的刷新路径中存在错误
ORA-00001: 违反唯一约束条件 (YANGTK.UN_MV_T_NAME)
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 794
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 851
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 832
ORA-06512: 在line 1

刷新失败了。解决这个问题的一个方法是对于物化视图不建立唯一约束,唯一性由基表保证。但是这种方法只对只读物化视图适用。而且,缺少唯一约束信息,可能会影响SQL的执行计划。

这种情况下,最好的解决方法是建立延迟约束。

SQL> ALTER TABLE MV_T DROP CONSTRAINT UN_MV_T_NAME;

表已更改。

SQL> ALTER TABLE MV_T ADD CONSTRAINT UN_MV_T_NAME UNIQUE (NAME) DEFERRABLE;

表已更改。

SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')

PL/SQL 过程已成功完成。

注意,延迟唯一约束对应的索引也必须是非唯一的(如果是唯一索引,延迟约束将没有意义),否则无法达到延迟约束的目的。

Oracle 10g New Features