C = Control
M = Meta = Alt|Esc
Del = Backspace
基本快捷键(Basic)
C-x C-f "find"文件, 即在缓冲区打开/新建一个文件
C-x C-s 保存文件
C-x C-w 使用其他文件名另存为文件
C-x C-v 关闭当前缓冲区文件并打开新文件
C-x i 在当前光标处插入文件
C-x b 新建/切换缓冲区
C-x C-b 显示缓冲区列表
C-x k 关闭当前缓冲区
C-z 挂起emacs
C-X C-c 关闭emacs
光标移动基本快捷键(Basic Movement)
C-f 后一个字符
C-b 前一个字符
C-p 上一行
C-n 下一行
M-f 后一个单词
M-b 前一个单词
C-a 行首
C-e 行尾
C-v 向下翻一页
M-v 向上翻一页
M-< 到文件开头
M-> 到文件末尾
编辑(Editint)
M-n 重复执行后一个命令n次
C-u 重复执行后一个命令4次
C-u n 重复执行后一个命令n次
C-d 删除(delete)后一个字符
M-d 删除后一个单词
Del 删除前一个字符
M-Del 删除前一个单词
C-k 移除(kill)一行
C-Space 设置开始标记 (例如标记区域)
C-@ 功能同上, 用于C-Space被操作系统拦截的情况
C-w 移除(kill)标记区域的内容
M-w 复制标记区域的内容
C-y 召回(yank)复制/移除的区域/行
M-y 召回更早的内容 (在kill缓冲区内循环)
C-x C-x 交换光标和标记
C-t 交换两个字符的位置
M-t 交换两个单词的位置
C-x C-t 交换两行的位置
M-u 使从光标位置到单词结尾处的字母变成大写
M-l 与M-u相反
M-c 使从光标位置开始的单词的首字母变为大写
重要快捷键(Important)
C-g 停止当前运行/输入的命令
C-x u 撤销前一个命令
M-x revert-buffer RETURN (照着这个输入)撤销上次存盘后所有改动
M-x recover-file RETURN 从自动存盘文件恢复
M-x recover-session RETURN 如果你编辑了几个文件, 用这个恢复
在线帮助(Online-Help)
C-h c 显示快捷键绑定的命令
C-h k 显示快捷键绑定的命令和它的作用
C-h l 显示最后100个键入的内容
C-h w 显示命令被绑定到哪些快捷键上
C-h f 显示函数的功能
C-h v 显示变量的含义和值
C-h b 显示当前缓冲区所有可用的快捷键
C-h t 打开emacs教程
C-h i 打开info阅读器
C-h C-f 显示emacs FAQ
C-h p 显示本机Elisp包的信息
搜索/替换(Seach/Replace)
C-s 向后搜索
C-r 向前搜索
C-g 回到搜索开始前的位置(如果你仍然在搜索模式中)
M-% 询问并替换(query replace)
Space或y 替换当前匹配
Del或n 不要替换当前匹配
. 仅仅替换当前匹配并退出(替换)
, 替换并暂停(按Space或y继续)
! 替换以下所有匹配
^ 回到上一个匹配位置
RETURN或q 退出替换
使用正则表达式(Regular expression)搜索/替换
可在正则表达式中使用的符号:
^ 行首
$ 行尾
. 单个字符
.* 任意多个(包括没有)字符
\< 单词开头
\> 单词结尾
[] 括号中的任意一个字符(例如[a-z]表示所有的小写字母)
M C-s RETURN 使用正则表达式向后搜索
M C-r RETURN 使用正则表达式向前搜索
C-s 增量搜索
C-s 重复增量搜索
C-r 向前增量搜索
C-r 重复向前增量搜索
M-x query-replace-regexp 使用正则表达式搜索并替换
窗口命令(Window Commands)
C-x 2 水平分割窗格
C-x 3 垂直分割窗格
C-x o 切换至其他窗格
C-x 0 关闭窗格
C-x 1 关闭除了光标所在窗格外所有窗格
C-x ^ 扩大窗格
M-x shrink-window 缩小窗格
M C-v 滚动其他窗格内容
C-x 4 f 在其他窗格中打开文件
C-x 4 0 关闭当前缓冲区和窗格
C-x 5 2 新建窗口(frame)
C-x 5 f 在新窗口中打开文件
C-x 5 o 切换至其他窗口
C-x 5 0 关闭当前窗口
书签命令(Bookmark commands)
C-x r m 在光标当前位置创建书签
C-x r b 转到书签
M-x bookmark-rename 重命名书签
M-x bookmark-delete 删除书签
M-x bookmark-save 保存书签
C-x r l 列出书签清单
d 标记等待删除
Del 取消删除标记
x 删除被标记的书签
r 重命名
s 保存列表内所有书签
f 转到当前书签指向的位置
m 标记在多窗口中打开
v 显示被标记的书签(或者光标当前位置的书签)
t 切换是否显示路径列表
w 显示当前文件路径
q 退出书签列表
M-x bookmark-write 将所有书签导出至指定文件
M-x bookmark-load 从指定文件导入书签
Shell
M-x shell 打开shell模式
C-c C-c 类似unix里的C-c(停止正在运行的程序)
C-d 删除光标后一个字符
C-c C-d 发送EOF
C-c C-z 挂起程序(unix下的C-z)
M-p 显示前一条命令
M-n 显示后一条命令
DIRectory EDitor (dired)
C-x d 打开dired
C(大写C) 复制
d 标记等待删除
D 立即删除
e或f 打开文件或目录
g 刷新当前目录
G 改变文件所属组(chgrp)
k 从屏幕上的列表里删除一行(不是真的删除)
m 用*标记
n 光标移动到下一行
o 在另一个窗格打开文件并移动光标
C-o 在另一个窗格打开文件但不移动光标
P 打印文件
q 退出dired
Q 在标记的文件中替换
R 重命名文件
u 移除标记
v 显示文件内容
x 删除有D标记的文件
Z 压缩/解压缩文件
M-Del 移除标记(默认为所有类型的标记)
~ 标记备份文件(文件名有~的文件)等待删除
# 标记自动保存文件(文件名形如#name#)等待删除
*/ 用*标记所有文件夹(用C-u */n移除标记)
= 将当前文件和标记文件(使用C-@标记而不是dired的m标记)比较
M-= 将当前文件和它的备份比较
! 对当前文件应用shell命令
M-} 移动光标至下一个用*或D标记的文件
M-{ 移动光标至上一个用*或D标记的文件
% d 使用正则表达式标记文件等待删除
% m 使用正则表达式标记文件为*
+ 新建文件夹
> 移动光标至后一个文件夹
< 移动光标至前一个文件夹
s 切换排序模式(按文件名/日期)
或许把这个命令归入这一类也很合适:
M-x speedbar 打开一个独立的目录显示窗口
Telnet
M-x telnet 打开telnet模式
C-d 删除后一个字符或发送EOF
C-c C-c 停止正在运行的程序(和unix下的C-c类似)
C-c C-d 发送EOF
C-c C-o 清除最后一个命令的输出
C-c C-z 挂起正在运行的命令
C-c C-u 移除前一行
M-p 显示前一条命令
Text
只能在text模式里使用
M-s 使当前行居中
M-S 使当前段落居中
M-x center-region 使被选中的区域居中
宏命令(Macro-commands)
C-x ( 开始定义宏
C-x ) 结束定义宏
C-x e 运行最近定义的宏
M-n C-x e 运行最近定义的宏n次
M-x name-last-kbd-macro 给最近定义的宏命名(用来保存)
M-x insert-kbd-macro 将已命名的宏保存到文件
M-x load-file 载入宏
编程(Programming)
M C-\ 自动缩进光标和标记间的区域
M-m 移动光标到行首第一个(非空格)字符
M-^ 将当前行接到上一行末尾处
M-; 添加缩进并格式化的注释
C, C++和Java模式
M-a 移动光标到声明的开始处
M-e 移动光标到声明的结尾处
M C-a 移动光标到函数的开始处
M C-e 移动光标到函数的结尾处
C-c RETURN 将光标移动到函数的开始处并标记到结尾处
C-c C-q 根据缩进风格缩进整个函数
C-c C-a 切换自动换行功能
C-c C-d 一次性删除光标后的一串空格(greedy delete)
为了实现下面的一些技术, 你需要在保存源代码的目录里运行"etags
*.c *.h *.cpp"(或者源代码的其他的扩展名)
M-.(点) 搜索标签
M-x tags-search ENTER 在所有标签里搜索(使用正则表达式)
M-,(逗号) 在tags-search里跳至下一个匹配处
M-x tags-query-replace 在设置过标签的所有文件里替换文本
GDB(调试器)
M-x gdb 在另一个的窗格中打开gdb
版本控制(Version Control)
C-x v d 显示当前目录下所有注册过的文件(show all registered files in this dir)
C-x v = 比较不同版本间的差异(show diff between versions)
C-x v u 移除上次提交之后的更改(remove all changes since last checkin)
C-x v ~ 在不同窗格中显示某个版本(show certain version in different window)
C-x v l 打印日志(print log)
C-x v i 标记文件等待添加版本控制(mark file for version control add)
C-x v h 给文件添加版本控制文件头(insert version control header into file)
C-x v r 获取命名过的快照(check out named snapshot)
C-x v s 创建命名的快照(create named snapshot)
C-x v a 创建gnu风格的更改日志(create changelog file in gnu-style)
2011年6月9日星期四
2011年4月20日星期三
CentOS 5.5 快速配置VNC Server
一、安装VNC Server
yum install vnc-server
二、启动VNC Server服务:使用vncserver命令
vncserver :n (n为桌面号)
三、配置VNC Server启动文件
首次创建 ~HOME/.vnc/xstartup时,指定的窗口管理器是twm,它是一个极小的窗口管理器,几乎每台 X Window 系统机器上都有twm。把twm &注释掉,加上gnome-session &
四、关闭VNC Server服务
vncserver -kill :桌面号
例如:关闭上面的vnc连接
vncserver -kill :1
五、VNC Server 高级设置
1、设置vncserver启动脚本(/etc/init.d/vncserver)实现系统自启动时启动vncserver。在/etc/rc.d/rc.local文件中加入下面行。
/etc/init.d/vncserver start
2、编辑/etc/sysconfig/vncservers
VNCSERVERS="1:root"
VNCSERVERARGS[1]="-geometry 1024x768"
在ARGS 中修改"1024x768"来适应自己的X桌面实际参数配置。可以在这里添加任何其他VNC服务器参数配置。在VNCSERVERS中修改 root 为你希望运行VNC桌面的用户。VNCSERVERS中的1表示VNC以桌面1运行,如果希望添加其他的桌面,可以修改配置如下:
VNCSERVERS="1:user1 2:user2 3:user3"
3、设置vnc server的访问密码
使用vncpasswd命令
4、使用以下命令启动VNC:
/etc/init.d/vncserver start
5、查看VNC Server启动情况
[root@CPAYNET005 ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5801 0.0.0.0:* LISTEN 5248/Xvnc
tcp 0 0 0.0.0.0:5901 0.0.0.0:* LISTEN 5248/Xvnc
tcp 0 0 0.0.0.0:6001 0.0.0.0:* LISTEN 5248/Xvnc
tcp 0 0 :::6001 :::* LISTEN 5248/Xvnc
注:如果在浏览器中通过web方式访问VNC则 端口为:5801,如果通过VNC客户端(比如VNC Viewer)来访问VNC则端口为:5901
2011年4月16日星期六
Java Concurrency In Practice读书笔记之Introduction
Benefits of Threads
1.Exploiting Multiple Processors
2.Simplicity of Modeling
A complicated, asynchronous workflow can be decomposed into a number of simpler, synchronous workflows each running in a separate thread, interacting only with each other at specific synchronization points.
3.Simplified Handling of Asynchronous Events
If an application goes to read from a socket when no data is available, read blocks until some data is available.If each request has its own thread, then blocking does not affect the processing of other requests.
4.More Responsive User Interfaces
Risks of Threads
1.Safety Hazards
@NotThreadSafe
public class UnsafeSequence {
private int value;
/** Returns a unique value. */
public int getNext() {
return value++;
}
}
2.Liveness Hazards
A liveness failure occurs when an activity gets into a state such that it is permanently unable to make forward progress. One form of liveness failure that canoccur in sequential programs is an inadvertent infinite loop, where the code that follows the loop never gets executed.Including deadlock, starvation, and livelock.
3.Performance Hazards
Performance issues subsume a broad range of problems, including poor service time, responsiveness, throughput, resource consumption, or scalability.Context switches are more frequent in applications with many threads, and have significant costs: saving and restoring execution context, loss of locality, and CPU time spent scheduling threads instead of running them. When threads share data, they must use synchronization mechanisms that can inhibit compiler optimizations, flush or invalidate memory caches, and create synchronization traffic on the shared memory bus. All these factors introduce additional performance costs.
1.Exploiting Multiple Processors
2.Simplicity of Modeling
A complicated, asynchronous workflow can be decomposed into a number of simpler, synchronous workflows each running in a separate thread, interacting only with each other at specific synchronization points.
3.Simplified Handling of Asynchronous Events
If an application goes to read from a socket when no data is available, read blocks until some data is available.If each request has its own thread, then blocking does not affect the processing of other requests.
4.More Responsive User Interfaces
Risks of Threads
1.Safety Hazards
@NotThreadSafe
public class UnsafeSequence {
private int value;
/** Returns a unique value. */
public int getNext() {
return value++;
}
}
2.Liveness Hazards
A liveness failure occurs when an activity gets into a state such that it is permanently unable to make forward progress. One form of liveness failure that canoccur in sequential programs is an inadvertent infinite loop, where the code that follows the loop never gets executed.Including deadlock, starvation, and livelock.
3.Performance Hazards
Performance issues subsume a broad range of problems, including poor service time, responsiveness, throughput, resource consumption, or scalability.Context switches are more frequent in applications with many threads, and have significant costs: saving and restoring execution context, loss of locality, and CPU time spent scheduling threads instead of running them. When threads share data, they must use synchronization mechanisms that can inhibit compiler optimizations, flush or invalidate memory caches, and create synchronization traffic on the shared memory bus. All these factors introduce additional performance costs.
2011年4月15日星期五
多表连接的三种方式详解(转)
多表之间的连接有三种方式:Nested Loops,Hash Join 和 Sort Merge Join. 下面来介绍三种不同连接的不同:
一. NESTED LOOP:
对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合),要把返回子集较小表的作为外表(CBO 默认外表是驱动表),而且在内表的连接字段上一定要有索引。当然也可以用ORDERED 提示来改变CBO默认的驱动表,使用USE_NL(table_name1 table_name2)可是强制CBO 执行嵌套循环连接。
Nested loop一般用在连接的表中有索引,并且索引选择性较好的时候.
步骤:确定一个驱动表(outer table),另一个表为inner table,驱动表中的每一行与inner表中的相应记录JOIN。类似一个嵌套的循环。适用于驱动表的记录集比较小(<10000)而且inner表需要有有效的访问方法(Index)。需要注意的是:JOIN的顺序很重要,驱动表的记录集一定要小,返回结果集的响应时间是最快的。
cost = outer access cost + (inner access cost * outer cardinality)
二. HASH JOIN :
散列连接是CBO 做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。
也可以用USE_HASH(table_name1 table_name2)提示来强制使用散列连接。如果使用散列连接HASH_AREA_SIZE 初始化参数必须足够的大,如果是9i,Oracle建议使用SQL工作区自动管理,设置WORKAREA_SIZE_POLICY 为AUTO,然后调整PGA_AGGREGATE_TARGET 即可。
Hash join在两个表的数据量差别很大的时候.
步骤:将两个表中较小的一个在内存中构造一个HASH表(对JOIN KEY),扫描另一个表,同样对JOIN KEY进行HASH后探测是否可以JOIN。适用于记录集比较大的情况。需要注意的是:如果HASH表太大,无法一次构造在内存中,则分成若干个partition,写入磁盘的temporary segment,则会多一个写的代价,会降低效率。
cost = (outer access cost * # of hash partitions) + inner access cost
三.SORT MERGE JOIN
通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。可以使用USE_MERGE(table_name1 table_name2)来强制使用排序合并连接.
Sort Merge join 用在没有索引,并且数据已经排序的情况.
cost = (outer access cost * # of hash partitions) + inner access cost
步骤:将两个表排序,然后将两个表合并。通常情况下,只有在以下情况发生时,才会使用此种JOIN方式:
1.RBO模式
2.不等价关联(>,<,>=,<=,<>)
3.HASH_JOIN_ENABLED=false
4.数据源已排序
四. 三种连接工作方式比较:
Hash join的工作方式是将一个表(通常是小一点的那个表)做hash运算,将列数据存储到hash列表中,从另一个表中抽取记录,做hash运算,到hash 列表中找到相应的值,做匹配。
Nested loops 工作方式是从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops适用的场合是当一个关联表比较小的时候,效率会更高。
Merge Join 是先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配,因为merge join需要做更多的排序,所以消耗的资源更多。 通常来讲,能够使用merge join的地方,hash join都可以发挥更好的性能。
一. NESTED LOOP:
对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合),要把返回子集较小表的作为外表(CBO 默认外表是驱动表),而且在内表的连接字段上一定要有索引。当然也可以用ORDERED 提示来改变CBO默认的驱动表,使用USE_NL(table_name1 table_name2)可是强制CBO 执行嵌套循环连接。
Nested loop一般用在连接的表中有索引,并且索引选择性较好的时候.
步骤:确定一个驱动表(outer table),另一个表为inner table,驱动表中的每一行与inner表中的相应记录JOIN。类似一个嵌套的循环。适用于驱动表的记录集比较小(<10000)而且inner表需要有有效的访问方法(Index)。需要注意的是:JOIN的顺序很重要,驱动表的记录集一定要小,返回结果集的响应时间是最快的。
cost = outer access cost + (inner access cost * outer cardinality)
二. HASH JOIN :
散列连接是CBO 做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。
也可以用USE_HASH(table_name1 table_name2)提示来强制使用散列连接。如果使用散列连接HASH_AREA_SIZE 初始化参数必须足够的大,如果是9i,Oracle建议使用SQL工作区自动管理,设置WORKAREA_SIZE_POLICY 为AUTO,然后调整PGA_AGGREGATE_TARGET 即可。
Hash join在两个表的数据量差别很大的时候.
步骤:将两个表中较小的一个在内存中构造一个HASH表(对JOIN KEY),扫描另一个表,同样对JOIN KEY进行HASH后探测是否可以JOIN。适用于记录集比较大的情况。需要注意的是:如果HASH表太大,无法一次构造在内存中,则分成若干个partition,写入磁盘的temporary segment,则会多一个写的代价,会降低效率。
cost = (outer access cost * # of hash partitions) + inner access cost
三.SORT MERGE JOIN
通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。可以使用USE_MERGE(table_name1 table_name2)来强制使用排序合并连接.
Sort Merge join 用在没有索引,并且数据已经排序的情况.
cost = (outer access cost * # of hash partitions) + inner access cost
步骤:将两个表排序,然后将两个表合并。通常情况下,只有在以下情况发生时,才会使用此种JOIN方式:
1.RBO模式
2.不等价关联(>,<,>=,<=,<>)
3.HASH_JOIN_ENABLED=false
4.数据源已排序
四. 三种连接工作方式比较:
Hash join的工作方式是将一个表(通常是小一点的那个表)做hash运算,将列数据存储到hash列表中,从另一个表中抽取记录,做hash运算,到hash 列表中找到相应的值,做匹配。
Nested loops 工作方式是从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops适用的场合是当一个关联表比较小的时候,效率会更高。
Merge Join 是先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配,因为merge join需要做更多的排序,所以消耗的资源更多。 通常来讲,能够使用merge join的地方,hash join都可以发挥更好的性能。
2011年4月9日星期六
Expert Oracle Database Architecture读书笔记之Transactions and Constraints
• Atomicity: Either all of a transaction happens or none of it happens.
• Consistency: A transaction takes the database from one consistent state to the next.
• Isolation: The effects of a transaction may not be visible to other transactions until the transaction has committed.
• Durability: Once the transaction is committed, it is permanent.
Transaction Control Statements
You should always explicitly terminate your transactions with a COMMIT or ROLLBACK; otherwise, the tool or environment you’re using will pick one or the other for you. If you exit your SQL*Plus session normally, without committing or rolling back, SQL*Plus assumes you wish to commit your work and it does so. If you just exit from a Pro*C program, on the other hand, an implicit rollback takes place. Never rely on implicit behavior, as it could change in the future. Always explicitly COMMIT or ROLLBACK your transactions.
Transaction control statements available to us:
• COMMIT:
• ROLLBACK:
• SAVEPOINT: A SAVEPOINT allows you to create a marked point within a transaction. You may have multiple SAVEPOINTs within a single transaction.
• ROLLBACK TO <SAVEPOINT>: This statement is used with the SAVEPOINT command. You can roll back your transaction to that marked point without rolling back any of the work that preceded it. So, you could issue two UPDATE statements, followed by a SAVEPOINT and then two DELETE statements. If an error or some sort of exceptional condition occurs during execution of the DELETE statements, and you catch that exception and issue the ROLLBACK TO SAVEPOINT command, the transaction will roll back to the named SAVEPOINT, undoing any work performed by the DELETEs but leaving the work performed by the UPDATE statements intact.
• SET TRANSACTION: This statement allows you to set various transaction attributes, such as the transaction’s isolation level and whether it is read-only or read-write.
Atomicity
Statement-Level Atomicity
Oracle achieves this statement-level atomicity by silently wrapping a SAVEPOINT around each of our calls to the database. The preceding two INSERTs were really treated like this:
Savepoint statement1;
Insert into t values ( 1 );
If error then rollback to statement1;
Savepoint statement2;
Insert into t values ( -1 );
If error then rollback to statement2;
In Oracle, this statement-level atomicity extends as deep as it needs to.If the INSERT INTO T fires a trigger that updates another table, and that table has a trigger that deletes from another table (and so on, and so on), either all of the work succeeds or none of it does. You don’t need to code anything special to ensure this; it’s just the way it works.
Procedure-Level Atomicity
Oracle treated the stored procedure call as an atomic statement. The client submitted a block of code—BEGIN P; END;—and Oracle wrapped a SAVEPOINT around it. Since P failed, Oracle restored the database back to the point right before it was called.
Transaction-Level Atomicity
DDL and Atomicity
Durability
Normally, when a transaction is committed, its changes are permanent—you can rely on those changes being in the database even if the database crashed the instant after the commit completed. This is not true, however, in two specific cases:
• You use the new (as of Oracle 10g Release 2 and above) WRITE extensions available in the COMMIT statement.
• You issue COMMITs in a non-distributed (accesses only a single database, no database links) PL/SQL block of code.
WRITE Extensions to COMMIT
Starting with Oracle Database 10g Release 2 and above, you may add a WRITE clause to your COMMIT
statements. The WRITE clause allows the commit to either WAIT for the redo you generated to be written to
disk (the default) or NOWAIT—to not wait—for the redo to be written. The NOWAIT option is the new capability—a capability that must be used carefully, with forethought, and with understanding of exactly what it means.
Normally, a COMMIT is a synchronous process. Your application invokes COMMIT and then your application waits for the entire COMMIT processing to be complete
When would you want to use this new capability to commit without waiting then? Three scenarios
come to mind:
• A custom data load program. It must be custom, since it will have additional logic to deal with the fact that a commit might not persist a system failure.
• An application that processes a live data feed of some sort, say a stock quote feed from the stock markets that inserts massive amounts of time-sensitive information into the database. If the database goes offline, the data stream keeps on going and the data generated during the system failure will never be processed (Nasdaq does not shut down because your database crashed, after all!). That this data is not processed is OK, because the stock data is so time-sensitive, after a few seconds it would be overwritten by new data anyway.
• An application that implements its own “queuing” mechanism, for example one that has data in a table with a PROCESSED_FLAG column. As new data arrives, it is inserted with a value of ROCESSED_FLAG='N' (unprocessed). Another routine is tasked with reading the PROCESSED_FLAG='N' records, performing some small, fast transaction and updating the PROCESSED_FLAG='N' to 'Y'. If it commits but that commit is later undone (by a system failure), it is OK because the application that processes these records will just process the record again—it is “restartable.”
COMMITS in a Non-Distributed PL/SQL Block
Since PL/SQL was first introduced in version 6 of Oracle, it has been transparently using an asynchronous commit. That approach has worked because all PL/SQL is like a batch program in a way—the end user does not know the outcome of the procedure until it is completely finished. That’s also why this asynchronous commit is used only in non-distributed PL/SQL blocks of code; if we involve more than one database, then there are two things—two databases—relying on the commit being durable. When two databases are relying on the commit being durable, we have to utilize synchronous protocols or a change might be committed in one database but not the other.
ops$tkyte%ORA11GR2> create table t
2 as
3 select *
4 from all_objects
5 where 1=0
6 /
Table created.
ops$tkyte%ORA11GR2> create or replace procedure p
2 as
3 begin
4 for x in ( select * from all_objects )
5 loop
6 insert into t values X;
7 commit;
8 end loop;
9 end;
10 /
Logically, that code is the same as:
ops$tkyte%ORA11GR2> create or replace procedure p
2 as
3 begin
4 for x in ( select * from all_objects )
5 loop
6 insert into t values X;
7 commit write NOWAIT;
8 end loop;
9
10 -- make internal call here to ensure
11 -- redo was written by LGWR
12 end;
13 /
Distributed Transactions
One of the really nice features of Oracle is its ability to transparently handle distributed transactions. I can update data in many different databases in the scope of a single transaction. When I commit, either I commit the updates in all of the instances or I commit none of them (they will all be rolled back). I need no extra code to achieve this; I simply “commit.” A key to distributed transactions in Oracle is the database link.
select * from T@another_database;
There are some, but not many, limitations to what you can do in a distributed transaction, and they are reasonable (to me, anyway, they seem reasonable). The big ones are as follows:
• You can’t issue a COMMIT over a database link. That is, you can’t issue a COMMIT@remote_site. You may commit only from the site that initiated the transaction.
• You can’t do DDL over a database link.
• You can’t issue a SAVEPOINT over a database link.
Autonomous Transactions
Autonomous transactions allow you to create a “transaction within a transaction” that will commit or roll back changes independently of its parent transaction. They allow you to suspend the currently executing transaction, start a new one, do some work, and commit or roll back—all without affecting the currently executing transaction state. Autonomous transactions provide a new method of controlling transactions in PL/SQL and may be used in
• Top-level anonymous blocks
• Local (a procedure in a procedure), stand-alone, or packaged functions and procedures
• Methods of object types
• Database triggers
How Autonomous Transactions Work
ops$tkyte%ORA11GR2> create or replace procedure Autonomous_Insert
2 as
3 pragma autonomous_transaction;
4 begin
5 insert into t values ( 'Autonomous Insert' );
6 commit;
7 end;
8 /
Note the use of the pragma AUTONOMOUS_TRANSACTION. This directive tells the database that this
procedure, when executed, is to be executed as a new autonomous transaction, independent from its parent transaction.
And here’s the “normal” NONAUTONOMOUS_INSERT procedure:
ops$tkyte%ORA11GR2> create or replace procedure NonAutonomous_Insert
2 as
3 begin
4 insert into t values ( 'NonAutonomous Insert' );
5 commit;
6 end;
7 /
Now let’s observe the behavior of the nonautonomous transaction in an anonymous block of
PL/SQL code:
ops$tkyte%ORA11GR2> begin
2 insert into t values ( 'Anonymous Block' );
3 NonAutonomous_Insert;
4 rollback;
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> select * from t;
MSG
-------------------------
Anonymous Block
NonAutonomous Insert
As you can see, the work performed by the anonymous block, its INSERT, was committed by the NONAUTONOMOUS_INSERT procedure. Both rows of data were committed, so the ROLLBACK command had nothing to roll back.
ops$tkyte%ORA11GR2> begin
2 insert into t values ( 'Anonymous Block' );
3 Autonomous_Insert;
4 rollback;
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> select * from t;
MSG
-------------------------
Autonomous Insert
Here, only the work done by and committed in the autonomous transaction persists. The INSERT done in the anonymous block was rolled back by the ROLLBACK statement on line 4. The autonomous transaction procedure’s COMMIT has no effect on the parent transaction started in the anonymous block.
Data Integrity
Techniques for Guaranteeing Data Integrity
When designing a database application, developers have various options for guaranteeing the integrity of data stored in the database. These options include:
・Enforcing business rules with triggered stored database procedures
・Using stored procedures to completely control access to data
・Enforcing business rules in the code of a database application
・Using Oracle Database integrity constraints, which are rules defined at the column or object level that restrict values in the database
Advantages of Integrity Constraints
The best practice is to enforce data integrity by means other than integrity constraints only when an integrity constraint cannot be used. Advantages of integrity constraints over alternatives for enforcing data integrity include:
・Declarative ease
Because you define integrity constraints using SQL statements, no additional programming is required when you define or alter a table. The SQL statements are easy to write and eliminate programming errors.
・Centralized rules
Integrity constraints are defined for tables and are stored in the data dictionary. Thus, data entered by all applications must adhere to the same integrity constraints. If the rules change at the table level, then applications need not change. Also, applications can use metadata in the data dictionary to immediately inform users of violations, even before the database checks the SQL statement.
・Flexibility when loading data
You can disable integrity constraints temporarily to avoid performance overhead when loading large amounts of data. When the data load is complete, you can re-enable the integrity constraints.
Types of Integrity Constraints
Oracle Database enables you to apply constraints both at the table and column level. A constraint specified as part of the definition of a column or attribute is called an inline specification. A constraint specified as part of the table definition is called an out-of-line specification.
Table 5-1 describes the types of constraints. Each can be specified either inline or out-of-line, except for NOT NULL, which must be inline.
• Consistency: A transaction takes the database from one consistent state to the next.
• Isolation: The effects of a transaction may not be visible to other transactions until the transaction has committed.
• Durability: Once the transaction is committed, it is permanent.
Transaction Control Statements
You should always explicitly terminate your transactions with a COMMIT or ROLLBACK; otherwise, the tool or environment you’re using will pick one or the other for you. If you exit your SQL*Plus session normally, without committing or rolling back, SQL*Plus assumes you wish to commit your work and it does so. If you just exit from a Pro*C program, on the other hand, an implicit rollback takes place. Never rely on implicit behavior, as it could change in the future. Always explicitly COMMIT or ROLLBACK your transactions.
Transaction control statements available to us:
• COMMIT:
• ROLLBACK:
• SAVEPOINT: A SAVEPOINT allows you to create a marked point within a transaction. You may have multiple SAVEPOINTs within a single transaction.
• ROLLBACK TO <SAVEPOINT>: This statement is used with the SAVEPOINT command. You can roll back your transaction to that marked point without rolling back any of the work that preceded it. So, you could issue two UPDATE statements, followed by a SAVEPOINT and then two DELETE statements. If an error or some sort of exceptional condition occurs during execution of the DELETE statements, and you catch that exception and issue the ROLLBACK TO SAVEPOINT command, the transaction will roll back to the named SAVEPOINT, undoing any work performed by the DELETEs but leaving the work performed by the UPDATE statements intact.
• SET TRANSACTION: This statement allows you to set various transaction attributes, such as the transaction’s isolation level and whether it is read-only or read-write.
Atomicity
Statement-Level Atomicity
Oracle achieves this statement-level atomicity by silently wrapping a SAVEPOINT around each of our calls to the database. The preceding two INSERTs were really treated like this:
Savepoint statement1;
Insert into t values ( 1 );
If error then rollback to statement1;
Savepoint statement2;
Insert into t values ( -1 );
If error then rollback to statement2;
In Oracle, this statement-level atomicity extends as deep as it needs to.If the INSERT INTO T fires a trigger that updates another table, and that table has a trigger that deletes from another table (and so on, and so on), either all of the work succeeds or none of it does. You don’t need to code anything special to ensure this; it’s just the way it works.
Procedure-Level Atomicity
Oracle treated the stored procedure call as an atomic statement. The client submitted a block of code—BEGIN P; END;—and Oracle wrapped a SAVEPOINT around it. Since P failed, Oracle restored the database back to the point right before it was called.
Transaction-Level Atomicity
DDL and Atomicity
Durability
Normally, when a transaction is committed, its changes are permanent—you can rely on those changes being in the database even if the database crashed the instant after the commit completed. This is not true, however, in two specific cases:
• You use the new (as of Oracle 10g Release 2 and above) WRITE extensions available in the COMMIT statement.
• You issue COMMITs in a non-distributed (accesses only a single database, no database links) PL/SQL block of code.
WRITE Extensions to COMMIT
Starting with Oracle Database 10g Release 2 and above, you may add a WRITE clause to your COMMIT
statements. The WRITE clause allows the commit to either WAIT for the redo you generated to be written to
disk (the default) or NOWAIT—to not wait—for the redo to be written. The NOWAIT option is the new capability—a capability that must be used carefully, with forethought, and with understanding of exactly what it means.
Normally, a COMMIT is a synchronous process. Your application invokes COMMIT and then your application waits for the entire COMMIT processing to be complete
When would you want to use this new capability to commit without waiting then? Three scenarios
come to mind:
• A custom data load program. It must be custom, since it will have additional logic to deal with the fact that a commit might not persist a system failure.
• An application that processes a live data feed of some sort, say a stock quote feed from the stock markets that inserts massive amounts of time-sensitive information into the database. If the database goes offline, the data stream keeps on going and the data generated during the system failure will never be processed (Nasdaq does not shut down because your database crashed, after all!). That this data is not processed is OK, because the stock data is so time-sensitive, after a few seconds it would be overwritten by new data anyway.
• An application that implements its own “queuing” mechanism, for example one that has data in a table with a PROCESSED_FLAG column. As new data arrives, it is inserted with a value of ROCESSED_FLAG='N' (unprocessed). Another routine is tasked with reading the PROCESSED_FLAG='N' records, performing some small, fast transaction and updating the PROCESSED_FLAG='N' to 'Y'. If it commits but that commit is later undone (by a system failure), it is OK because the application that processes these records will just process the record again—it is “restartable.”
COMMITS in a Non-Distributed PL/SQL Block
Since PL/SQL was first introduced in version 6 of Oracle, it has been transparently using an asynchronous commit. That approach has worked because all PL/SQL is like a batch program in a way—the end user does not know the outcome of the procedure until it is completely finished. That’s also why this asynchronous commit is used only in non-distributed PL/SQL blocks of code; if we involve more than one database, then there are two things—two databases—relying on the commit being durable. When two databases are relying on the commit being durable, we have to utilize synchronous protocols or a change might be committed in one database but not the other.
ops$tkyte%ORA11GR2> create table t
2 as
3 select *
4 from all_objects
5 where 1=0
6 /
Table created.
ops$tkyte%ORA11GR2> create or replace procedure p
2 as
3 begin
4 for x in ( select * from all_objects )
5 loop
6 insert into t values X;
7 commit;
8 end loop;
9 end;
10 /
Logically, that code is the same as:
ops$tkyte%ORA11GR2> create or replace procedure p
2 as
3 begin
4 for x in ( select * from all_objects )
5 loop
6 insert into t values X;
7 commit write NOWAIT;
8 end loop;
9
10 -- make internal call here to ensure
11 -- redo was written by LGWR
12 end;
13 /
Distributed Transactions
One of the really nice features of Oracle is its ability to transparently handle distributed transactions. I can update data in many different databases in the scope of a single transaction. When I commit, either I commit the updates in all of the instances or I commit none of them (they will all be rolled back). I need no extra code to achieve this; I simply “commit.” A key to distributed transactions in Oracle is the database link.
select * from T@another_database;
There are some, but not many, limitations to what you can do in a distributed transaction, and they are reasonable (to me, anyway, they seem reasonable). The big ones are as follows:
• You can’t issue a COMMIT over a database link. That is, you can’t issue a COMMIT@remote_site. You may commit only from the site that initiated the transaction.
• You can’t do DDL over a database link.
• You can’t issue a SAVEPOINT over a database link.
Autonomous Transactions
Autonomous transactions allow you to create a “transaction within a transaction” that will commit or roll back changes independently of its parent transaction. They allow you to suspend the currently executing transaction, start a new one, do some work, and commit or roll back—all without affecting the currently executing transaction state. Autonomous transactions provide a new method of controlling transactions in PL/SQL and may be used in
• Top-level anonymous blocks
• Local (a procedure in a procedure), stand-alone, or packaged functions and procedures
• Methods of object types
• Database triggers
How Autonomous Transactions Work
ops$tkyte%ORA11GR2> create or replace procedure Autonomous_Insert
2 as
3 pragma autonomous_transaction;
4 begin
5 insert into t values ( 'Autonomous Insert' );
6 commit;
7 end;
8 /
Note the use of the pragma AUTONOMOUS_TRANSACTION. This directive tells the database that this
procedure, when executed, is to be executed as a new autonomous transaction, independent from its parent transaction.
And here’s the “normal” NONAUTONOMOUS_INSERT procedure:
ops$tkyte%ORA11GR2> create or replace procedure NonAutonomous_Insert
2 as
3 begin
4 insert into t values ( 'NonAutonomous Insert' );
5 commit;
6 end;
7 /
Now let’s observe the behavior of the nonautonomous transaction in an anonymous block of
PL/SQL code:
ops$tkyte%ORA11GR2> begin
2 insert into t values ( 'Anonymous Block' );
3 NonAutonomous_Insert;
4 rollback;
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> select * from t;
MSG
-------------------------
Anonymous Block
NonAutonomous Insert
As you can see, the work performed by the anonymous block, its INSERT, was committed by the NONAUTONOMOUS_INSERT procedure. Both rows of data were committed, so the ROLLBACK command had nothing to roll back.
ops$tkyte%ORA11GR2> begin
2 insert into t values ( 'Anonymous Block' );
3 Autonomous_Insert;
4 rollback;
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> select * from t;
MSG
-------------------------
Autonomous Insert
Here, only the work done by and committed in the autonomous transaction persists. The INSERT done in the anonymous block was rolled back by the ROLLBACK statement on line 4. The autonomous transaction procedure’s COMMIT has no effect on the parent transaction started in the anonymous block.
Data Integrity
Techniques for Guaranteeing Data Integrity
When designing a database application, developers have various options for guaranteeing the integrity of data stored in the database. These options include:
・Enforcing business rules with triggered stored database procedures
・Using stored procedures to completely control access to data
・Enforcing business rules in the code of a database application
・Using Oracle Database integrity constraints, which are rules defined at the column or object level that restrict values in the database
Advantages of Integrity Constraints
The best practice is to enforce data integrity by means other than integrity constraints only when an integrity constraint cannot be used. Advantages of integrity constraints over alternatives for enforcing data integrity include:
・Declarative ease
Because you define integrity constraints using SQL statements, no additional programming is required when you define or alter a table. The SQL statements are easy to write and eliminate programming errors.
・Centralized rules
Integrity constraints are defined for tables and are stored in the data dictionary. Thus, data entered by all applications must adhere to the same integrity constraints. If the rules change at the table level, then applications need not change. Also, applications can use metadata in the data dictionary to immediately inform users of violations, even before the database checks the SQL statement.
・Flexibility when loading data
You can disable integrity constraints temporarily to avoid performance overhead when loading large amounts of data. When the data load is complete, you can re-enable the integrity constraints.
Types of Integrity Constraints
Oracle Database enables you to apply constraints both at the table and column level. A constraint specified as part of the definition of a column or attribute is called an inline specification. A constraint specified as part of the table definition is called an out-of-line specification.
Table 5-1 describes the types of constraints. Each can be specified either inline or out-of-line, except for NOT NULL, which must be inline.
Nulls and Foreign Keys
The relational model permits the value of foreign keys to match either the referenced primary or unique key value, or be null. For example, a user could insert a row into hr.employees without specifying a department ID.
Parent Key Modifications and Foreign Keys
When a parent key is modified, referential integrity constraints can specify the following actions to be performed on dependent rows in a child table:
・No action on deletion or update
In the normal case, users cannot modify referenced key values if the results would violate referential integrity.
・Cascading deletions
A deletion cascades (DELETE CASCADE) when rows containing referenced key values are deleted, causing all rows in child tables with dependent foreign key values to also be deleted.
・Deletions that set null
A deletion sets null (DELETE SET NULL) when rows containing referenced key values are deleted, causing all rows in child tables with dependent foreign key values to set those values to null.
Indexes and Foreign Keys
As a rule, foreign keys should be indexed. The only exception is when the matching unique or primary key is never updated or deleted. Indexing the foreign keys in child tables provides the following benefits:
・Prevents a full table lock on the child table. Instead, the database acquires a row lock on the index.
・Removes the need for a full table scan of the child table. As an illustration, assume that a user removes the record for for department 10 from the departments table.
States of Integrity Constraints
Checks for Modified and Existing Data
You can set constraints to validate (
VALIDATE
) or not validate (NOVALIDATE
) existing data. If VALIDATE
is specified, then existing data must conform to the constraint. For example, enabling a NOT NULL
constraint on employees.department_id
and setting it to VALIDATE
checks that every existing row has a department ID. If NOVALIDATE
is specified, then existing data need not conform to the constraint.Deferrable Constraints
Every constraint is either in a not deferrable (default) or deferrable state. This state determines when Oracle Database checks the constraint for validity.
Nondeferrable Constraints
If a constraint is not deferrable, then Oracle Database never defers the validity check of the constraint to the end of the transaction. Instead, the database checks the constraint at the end of each statement. If the constraint is violated, then the statement rolls back.
For example, assume that you create a nondeferrable NOT NULL constraint for the employees.last_name column. If a user attempts to insert a row with no last name, then the database immediately rolls back the statement because the NOT NULL constraint is violated. No row is inserted.
Deferrable Constraints
A deferrable constraint permits a transaction to use the SET CONSTRAINT clause to defer checking of this constraint until a COMMIT statement is issued. If you make changes to the database that might violate the constraint, then this setting effectively lets you disable the constraint until all the changes are complete.
You can set the default behavior for when the database checks the deferrable constraint. You can specify either of the following attributes:
・INITIALLY IMMEDIATE
The database checks the constraint immediately after each statement executes. If the constraint is violated, then the database rolls back the statement.
・INITIALLY DEFERRED
The database checks the constraint when a COMMIT is issued. If the constraint is violated, then the database rolls back the transaction.
2011年4月8日星期五
Expert Oracle Database Architecture读书笔记之Concurrency and Multi-versioning
Transaction Isolation Levels
These isolation levels are defined in terms of three “phenomena” that are either permitted or not at a given isolation level:
• Dirty read: The meaning of this term is as bad as it sounds. You are permitted to read uncommitted, or dirty, data. You would achieve this effect by just opening an OS file that someone else is writing and reading whatever data happens to be there. Data integrity is compromised, foreign keys are violated, and unique constraints are ignored.
• Non-repeatable read: This simply means that if you read a row at time T1 and attempt to reread that row at time T2, the row may have changed, it may have disappeared, it may have been updated, and so on.
• Phantom read: This means that if you execute a query at time T1 and re-execute it at time T2, additional rows may have been added to the database, which will affect your results. This differs from the non-repeatable read in that with a phantomread, data you already read has not been changed, but rather that more data satisfies your query criteria than before.
The SQL isolation levels are defined based on whether or not they allow each of the preceding phenomena.
These isolation levels are defined in terms of three “phenomena” that are either permitted or not at a given isolation level:
• Dirty read: The meaning of this term is as bad as it sounds. You are permitted to read uncommitted, or dirty, data. You would achieve this effect by just opening an OS file that someone else is writing and reading whatever data happens to be there. Data integrity is compromised, foreign keys are violated, and unique constraints are ignored.
• Non-repeatable read: This simply means that if you read a row at time T1 and attempt to reread that row at time T2, the row may have changed, it may have disappeared, it may have been updated, and so on.
• Phantom read: This means that if you execute a query at time T1 and re-execute it at time T2, additional rows may have been added to the database, which will affect your results. This differs from the non-repeatable read in that with a phantomread, data you already read has not been changed, but rather that more data satisfies your query criteria than before.
The SQL isolation levels are defined based on whether or not they allow each of the preceding phenomena.
Isolation Level | Dirty Read | Nonrepeatable Read | Phantom Read |
Possible | Possible | Possible | |
Read committed | Not possible | Possible | Possible |
Not possible | Not possible | Possible | |
Serializable | Not possible | Not possible | Not possible |
Oracle Database provides the transaction isolation levels:
-Read Committed Isolation
-Serializable Isolation
-Read-Only Isolation
READ UNCOMMITTED
UPDATE statements have two components: a read component as defined by the WHERE clause and a write component as defined by the SET clause. UPDATE statements read and write to the database; all DML statements have this ability. The case of a single row INSERT using the VALUES clause is the only exception, as such statements have no read component, just the write component.
READ COMMITTED
In the read committed isolation level, which is the default, every query executed by a transaction sees only data committed before the query—not the transaction—began.
There are no dirty reads. There may be non-repeatable reads (i.e., rereads of the same row may return a different answer in the same transaction) and phantom reads (i.e., newly inserted and committed rows become visible to a query that were not visible earlier in the transaction). READ COMMITTED is perhaps the most commonly used isolation level in database applications everywhere, and it is the default mode for Oracle databases.
The really bad news in the read committed is that we are may make the end user wait for the wrong answer. We still receive an answer that never existed in the committed database state at any point in time, as with the dirty read, but this time we made the user wait for the wrong answer.
REPEATABLE READ
The goal of REPEATABLE READ is to provide an isolation level that gives consistent, correct answers and
prevents lost updates.
Most databases (not Oracle) achieve repeatable reads via the use of row-level shared read locks. A shared read lock prevents other sessions from modifying data that we have read. This, of course, decreases concurrency. Oracle opted for the more concurrent, multi-versioning model to provide read-consistent answers.
In Oracle, using multi-versioning, we get an answer that is consistent with respect to the point in time the query began execution.
If we have REPEATABLE READ enabled in a database that employs shared read locks (and not multi-
versioning), lost update errors can’t happen. The reason lost updates will not happen in those databases is because the simple act of selecting the data leaves a lock on it, and once read by our transaction, that data cannot be modified by any other transaction. Now, if your application assumes that REPEATABLE READ implies “lost updates can’t happen,” you are in for a painful surprise when you move your application to a database that does not use shared read locks as an underlying concurrency control mechanism.
SERIALIZABLE
In the serialization isolation level, a transaction sees only changes committed at the time the transaction—not the query—began and changes made by the transaction itself.
Oracle takes an optimistic approach to serialization—it gambles on the fact that the data your transaction wants to update won’t be updated by any other transaction. This is typically the way it happens, and usually the gamble pays off, especially in quick-transaction, OLTP-type systems. If no one else updates your data during your transaction, this isolation level, which will generally decrease concurrency in other systems, will provide the same degree of concurrency as it would without SERIALIZABLE transactions. The downside to this is that you may get the ORA-08177 error if the gamble doesn’t pay off. If you think about it, however, it’s worth the risk. If you’re using SERIALIZABLE transactions, you shouldn’t expect to update the same information as other transactions. If you do, you should use the SELECT ... FOR UPDATE.
In many other implementations, you will find this being achieved with shared read locks and their corresponding deadlocks, and blocking. In Oracle, we do not get any blocking, but we will get the ORA-08177 error if other sessions change the data we want to change as well.
READ ONLY
READ ONLY transactions are very similar to SERIALIZABLE transactions, the only difference being that they do not allow modifications, so they are not susceptible to the ORA-08177 error. READ ONLY transactions are intended to support reporting needs where the contents of the report need to be consistent with respect to a single point in time. In other systems, you would use REPEATABLE READ and suffer the associated affects of the shared read lock.
READ ONLY transactions are not trouble-free, however. Whereas you might see an ORA-08177 error in a SERIALIZABLE transaction, you expect to see an ORA-01555 snapshot too old error with READ ONLY
transactions. This will happen on a system where other people are actively modifying the information you are reading. The changes (undo) made to this information are recorded in the undo segments. But undo segments are used in a circular fashion in much the same manner as redo logs. The longer the report takes to run, the better the chance that some undo you need to reconstruct your data won’t be there anymore. The undo segment will have wrapped around, and the portion of it you need would be reused by some other transaction. At this point, you will receive the ORA-01555 error and have to start over again.
The only solution to this sticky issue is to have undo segments that are sized correctly for your system. Time and time again, I see people trying to save a few megabytes of disk space by having the smallest possible undo segments (“Why ‘waste’ space on something I don’t really need?” is the thought). The problem is that the undo segments are a key component of the way the database works, and unless they are sized correctly, you will hit this error.
Implications of Multi-version Read Consistency
A Common Data Warehousing Technique That Fails
A common data warehousing technique I’ve seen people employ goes like this:
1. They use a trigger to maintain a LAST_UPDATED column in the source table, much like the method described in the last chapter in the “Optimistic Locking” section.
2. To initially populate a data warehouse table, they remember what time it is right now by selecting out SYSDATE on the source system. For example, suppose it is exactly 9:00 a.m. right now.
3. They then pull all of the rows from the transactional system—a full SELECT * FROM TABLE—to get the data warehouse initially populated.
4. To refresh the data warehouse, they remember what time it is right now again. For example, suppose an hour has gone by—it is now 10:00 a.m. on the source system. They will remember that fact. They then pull all changed records since 9:00 a.m. (the moment before they started the first pull) and merge them in.
They believe that they now have all of the records in the data warehouse that were modified since they did the initial pull. They may actually have all of the records, but just as likely they may not. This technique does work on some other databases—ones that employ a locking system whereby reads are blocked by writes and vice versa. But in a system where you have non-blocking reads, the logic is flawed.
To see the flaw in this example, all we need to do is assume that at 9:00 a.m. there was at least one open, uncommitted transaction. At 8:59:30 a.m., it had updated a row in the table we were to copy. At 9:00 a.m., when we started pulling the data and thus reading the data in this table, we would not see the modifications to that row; we would see the last committed version of it. If it was locked when we got to it in our query, we would read around the lock. If it was committed by the time we got to it, we would still read around it since read consistency permits us to read only data that was committed in the database when our statement began. We would not read that new version of the row during the 9:00 a.m. initial pull, nor would we read the modified row during the 10:00 a.m. refresh. The reason? The 10:00 a.m. refresh would only pull records modified since 9:00 a.m. that morning, but this record was modified at 8:59:30 a.m. We would never pull this changed record. In many other databases where reads are blocked by writes and a committed but inconsistent read is implemented, this refresh process would work perfectly. If at 9:00 a.m. when we did the initial pull of data, we hit that row and it was locked, we would have blocked and waited for it, and read the
committed version. If it were not locked, we would just read whatever was there, committed. So, does this mean the preceding logic just cannot be used? No, it means that we need to get the “right now” time a little differently. We need to query V$TRANSACTION and find out which is the earliest of the current time and the time recorded in START_TIME column of this view. We will need to pull all records changed since the start time of the oldest transaction (or the current SYSDATE value if there are no active transactions):
select nvl( min(to_date(start_time,'mm/dd/rr hh24:mi:ss')),sysdate) from v$transaction;
In this example, that would be 8:59:30 a.m. when the transaction that modified the row started. When we go to refresh the data at 10:00 a.m., we pull all of the changes that had occurred since that time; when we merge these into the data warehouse, we’ll have everything we need.
Write Consistency
Consistent Reads and Current Reads
Oracle does do two types of block gets when processing a modification statement. It performs
• Consistent reads: When “finding” the rows to modify
• Current reads: When getting the block to actually update the row of interest
现用Oracle执行update的过程来说明Write Consistency:
1)根据条件作一致读。该一致读SCN为update statement开始的时间。
2)一致读中找到满足条件的记录。(this row,when we started at update-statement SCN,was interested by us )
3)然后以当前模式(current mode)读取到数据块最新的内容(row,when was interested in consistent read),然后比较一致读和当前读的数据集。
4)如果没有使用触发器,则只比较在where中出现的列 (predicate in consistent read) ;如果包括触发器,则还需要比较trigger内引用的:old 列。因为oracle是在一致读模式得到:old值,且在当前模式:old列可能会被改变了。
5) 如果predicate 发生变化,则表示受到其他事务影响,则mini-rollback. 否则正常更新。assuming you are using READ COMMITTED isolation. If you are using SERIALIZABLE isolation, then at this point you would receive an ORA-08177: can't serialize access for this transaction error.
举个例子,如果执行update t set x = 5 where y = 6;
consistent read中y=6为最后一行,则通过consistent read找到该纪录;然后以current read 读取该块;但是发现该纪录已经被其他session将"y=6" update为 "y=7"( Tx-another), 表示该session执行的update的状态不一致,导致mini-rollback.
In READ COMMITTED mode, after the transaction rolls back your update, the database will restart the update (i.e., change the point in time at which the update is “as of”), and instead of updating the data again, it will go into SELECT FOR UPDATE mode and attempt to lock all of the rows WHERE Y=6 for your session. Once it does this, it will run the UPDATE against that locked set of data, thus ensuring this time that it can complete without restarting.
因此,在batch更新之前,避免&减少mini-rollback的方法就是先select for update获得锁,再更新。
2011年4月2日星期六
Expert Oracle Database Architecture读书笔记之Locking and Latching
Pessimistic Locking
A row lock would be placed as soon as the user indicates his intention to perform an update on a specific row that he has selected and has visible on the screen (by clicking a button on the screen, say). That row lock would persist until the application applied the users' modifications to the row in the database and committed.
Optimistic Locking
optimistic locking, defers all locking up to the point right before the
There are many methods of implementing optimistic concurrency control. We’ve discussed one whereby the application will store all of the before images of the row in the application itself. In the following sections, we’ll explore two others, namely:
• Using a special column that is maintained by a database trigger or application code to tell us the “version” of the record
• Using a checksum or hash that was computed using the original data
Optimistic Locking Using a Version Column
This is a simple implementation that involves adding a single column to each database table you wish to protect from lost updates. This column is generally either a NUMBER or DATE/TIMESTAMP column. It is typically maintained via a row trigger on the table, which is responsible for incrementing the NUMBER column or updating the DATE/TIMESTAMP column every time a row is modified.
I would personally prefer this column be maintained by the UPDATE statement itself, not via a trigger because triggers that are not absolutely necessary (as this one is) should be avoided. For background on why I avoid triggers, refer to my “Trouble With Triggers” article from Oracle Magazine, found on the Oracle Technology Network at http://www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html.
Optimistic Locking Using a Checksum
This is very similar to the previous version column method, but it uses the base data itself to compute a “virtual” version column. I’ll quote the Oracle 11g Release 2 PL/SQL Supplied Packages Guide (before showing how to use one of the supplied packages!) to help explain the goal and concepts behind a checksum or hash function:
A one-way hash function takes a variable-length input string, the data, and converts it to a fixed-length (generally smaller) output string called a hash value. The hash value serves as a unique identifier (like a fingerprint) of the input data. You can use the hash value to verify whether data has been changed or not.
Optimistic or Pessimistic Locking?
Today, however, optimistic concurrency control is what I would recommend for most
large columns.
Blocked Inserts
There are few times when an INSERT will block. The most common scenario is when you have a table with a primary key or unique constraint placed on it and two sessions attempt to insert a row with the same value. One of the sessions will block until the other session either commits (in which case the blocked session will receive an error about a duplicate value) or rolls back (in which case the blocked session succeeds). Another case involves tables linked together via referential integrity constraints. An INSERT into a child table may become blocked if the parent row it depends on is being created or deleted.
Deadlocks
The number one cause of deadlocks in the Oracle database, in my experience, is unindexed foreign keys. (The number two cause is bitmap indexes on tables subject to concurrent updates, which we’ll cover in Chapter 11 “Indexes”). Oracle will place a full table lock on a child table after modification of the parent table in three scenarios:
• If you update the parent table’s primary key (a very rare occurrence if you follow the rule of relational databases stating that primary keys should be immutable), the child table will be locked in the absence of an index on the foreign key.
• If you delete a parent table row, the entire child table will be locked (in the absence of an index on the foreign key) as well.
• If you merge into the parent table, the entire child table will be locked (in the absence of an index on the foreign key) as well. Note this is only true in Oracle 9i and 10g and is no longer true in Oracle 11g Release 1 and above.
An unindexed foreign key can also be problematic in the following cases:
• When you have an ON DELETE CASCADE and have not indexed the child table. For example, EMP is child of DEPT. DELETE DEPTNO = 10 should CASCADE to EMP. If DEPTNO in EMP is not indexed, you will get a full table scan of EMP for each row deleted from the DEPT table. This full scan is probably undesirable, and if you delete many rows from the parent table, the child table will be scanned once for each parent row deleted.
• When you query from the parent to the child. Consider the EMP/DEPT example again. It is very common to query the EMP table in the context of a DEPTNO. If you frequently run the following query (say, to generate a report), you’ll find that not having the index in place will slow down the queries:
select * from dept, emp where emp.deptno = dept.deptno and dept.deptno = :X;
When do you not need to index a foreign key? The answer is, in general, when the following
conditions are met:
• You do not delete from the parent table.
• You do not update the parent table’s unique/primary key value (watch for unintended updates to the primary key by tools!).
• You do not join from the parent to the child (like DEPT to EMP).
Lock Escalation
If you select a row from a table with the
• DML locks: DML stands for Data Manipulation Language. In general this means
DML locks are used to ensure that only one person at a time modifies a row and that no one can drop a
In a database with a traditional memory-based lock manager, the process of locking a row would
resemble the following:
1. Find the address of the row you want to lock.
2. Get in line at the lock manager (which must be serialized, as it is a common in-
3. Lock the list.
4. Search through the list to see if anyone else has locked this row.
5. Create a new entry in the list to establish the fact that you have locked the row.
6. Unlock the list.
Now that you have the row locked, you can modify it. Later, as you commit your changes, you must continue the procedure as follows:
1. Get in line again.
2. Lock the list of locks.
3. Search through the list and release all of your locks.
4. Unlock the list
As you can see, the more locks acquired, the more time spent on this operation, both before and after modifying the data. Oracle does not do it that way. Oracle’s process looks like this:
1. Find the address of the row you want to lock.
2. Go to the row.
3. Lock the row right there, right then—at the location of the row, not in a big list somewhere (waiting for the transaction that has it locked to end if it is already locked, unless you are using the NOWAIT option).
In Chapter 10 “Database Tables”, we’ll get into the details of the block format, but suffice it to say that at the top of a database block is some leading overhead space in which to store a transaction table for that block. This transaction table contains an entry for each real transaction that has locked some data in that block. The size of this structure is controlled by two physical attribute parameters on the CREATE statement for an object:
• INITRANS: The initial, preallocated size of this structure. This defaults to 2 for indexes and tables.
• MAXTRANS: The maximum size to which this structure may grow. It defaults to 255 and has a minimum of 2 practically. In Oracle 10g and above, this setting has been deprecated, so it no longer applies. MAXTRANS is 255 regardless in that release and later.
Each block starts life with, by default, two transaction slots. The number of simultaneous active transactions that a block can ever have is constrained by the value of MAXTRANS and by the availability of space on the block. You may not be able to achieve 255 concurrent transactions on the block if there is
not sufficient space to grow this structure.
TM (DML Enqueue) Locks
TM locks are used to ensure that the structure of a table is not altered while you are modifying its
contents. For example, if you have updated a table, you will acquire a TM lock on that table. This will
drop table dept
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified
DDL Locks
DDL locks are automatically placed against objects during a DDL operation to protect them from changes by other sessions. For example, if I perform the DDL operation ALTER TABLE T, the table T will in
There are three types of DDL locks:
• Exclusive DDL locks: These prevent other sessions from gaining a DDL lock or TM (DML) lock themselves. This means that you may query a table during a DDL operation, but you may not modify it in any way.
• Share DDL locks: These protect the structure of the referenced object against modification by other sessions, but allow modifications to the data.
• Breakable parse locks: These allow an object, such as a query plan cached in the shared pool, to register its reliance on some other object. If you perform DDL against that object, Oracle will review the list of objects that have registered their dependence and invalidate them. Hence, these locks are breakable—they do not prevent the DDL from occurring.
Latches
Latches are lightweight serialization devices used to coordinate multiuser access to shared data structures, objects, and files.
A row lock would be placed as soon as the user indicates his intention to perform an update on a specific row that he has selected and has visible on the screen (by clicking a button on the screen, say). That row lock would persist until the application applied the users' modifications to the row in the database and committed.
Optimistic Locking
optimistic locking, defers all locking up to the point right before the
update is performed.
There are many methods of implementing optimistic concurrency control. We’ve discussed one whereby the application will store all of the before images of the row in the application itself. In the following sections, we’ll explore two others, namely:
• Using a special column that is maintained by a database trigger or application code to tell us the “version” of the record
• Using a checksum or hash that was computed using the original data
Optimistic Locking Using a Version Column
This is a simple implementation that involves adding a single column to each database table you wish to protect from lost updates. This column is generally either a NUMBER or DATE/TIMESTAMP column. It is typically maintained via a row trigger on the table, which is responsible for incrementing the NUMBER column or updating the DATE/TIMESTAMP column every time a row is modified.
I would personally prefer this column be maintained by the UPDATE statement itself, not via a trigger because triggers that are not absolutely necessary (as this one is) should be avoided. For background on why I avoid triggers, refer to my “Trouble With Triggers” article from Oracle Magazine, found on the Oracle Technology Network at http://www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html.
Optimistic Locking Using a Checksum
This is very similar to the previous version column method, but it uses the base data itself to compute a “virtual” version column. I’ll quote the Oracle 11g Release 2 PL/SQL Supplied Packages Guide (before showing how to use one of the supplied packages!) to help explain the goal and concepts behind a checksum or hash function:
A one-way hash function takes a variable-length input string, the data, and converts it to a fixed-length (generally smaller) output string called a hash value. The hash value serves as a unique identifier (like a fingerprint) of the input data. You can use the hash value to verify whether data has been changed or not.
Optimistic or Pessimistic Locking?
Today, however, optimistic concurrency control is what I would recommend for most
applications. Having a connection for the entire duration of a transaction is just too high a price to pay.
Of the methods available, which do I use? I tend to use the version column approach with a
timestamp column. It gives me the extra update information in a long-term sense. Furthermore, it’s less
computationally expensive than a hash or checksum, and it doesn’t run into the issues potentially
encountered with a hash or checksum when processing LONG, LONG RAW, CLOB, BLOB, and other verylarge columns.
Blocked Inserts
There are few times when an INSERT will block. The most common scenario is when you have a table with a primary key or unique constraint placed on it and two sessions attempt to insert a row with the same value. One of the sessions will block until the other session either commits (in which case the blocked session will receive an error about a duplicate value) or rolls back (in which case the blocked session succeeds). Another case involves tables linked together via referential integrity constraints. An INSERT into a child table may become blocked if the parent row it depends on is being created or deleted.
Deadlocks
The number one cause of deadlocks in the Oracle database, in my experience, is unindexed foreign keys. (The number two cause is bitmap indexes on tables subject to concurrent updates, which we’ll cover in Chapter 11 “Indexes”). Oracle will place a full table lock on a child table after modification of the parent table in three scenarios:
• If you update the parent table’s primary key (a very rare occurrence if you follow the rule of relational databases stating that primary keys should be immutable), the child table will be locked in the absence of an index on the foreign key.
• If you delete a parent table row, the entire child table will be locked (in the absence of an index on the foreign key) as well.
• If you merge into the parent table, the entire child table will be locked (in the absence of an index on the foreign key) as well. Note this is only true in Oracle 9i and 10g and is no longer true in Oracle 11g Release 1 and above.
An unindexed foreign key can also be problematic in the following cases:
• When you have an ON DELETE CASCADE and have not indexed the child table. For example, EMP is child of DEPT. DELETE DEPTNO = 10 should CASCADE to EMP. If DEPTNO in EMP is not indexed, you will get a full table scan of EMP for each row deleted from the DEPT table. This full scan is probably undesirable, and if you delete many rows from the parent table, the child table will be scanned once for each parent row deleted.
• When you query from the parent to the child. Consider the EMP/DEPT example again. It is very common to query the EMP table in the context of a DEPTNO. If you frequently run the following query (say, to generate a report), you’ll find that not having the index in place will slow down the queries:
select * from dept, emp where emp.deptno = dept.deptno and dept.deptno = :X;
When do you not need to index a foreign key? The answer is, in general, when the following
conditions are met:
• You do not delete from the parent table.
• You do not update the parent table’s unique/primary key value (watch for unintended updates to the primary key by tools!).
• You do not join from the parent to the child (like DEPT to EMP).
Lock Escalation
If you select a row from a table with the
FOR UPDATE clause, two locks will be created. One lock is placed on the row(s) you selected (and this will
be an exclusive lock; no one else can lock that specific row in exclusive mode). The other lock, a ROW
SHARE TABLE lock, is placed on the table itself. This will prevent other sessions from placing an exclusive
lock on the table and thus prevent them from altering the structure of the table.
Lock Types
The three general classes of locks in Oracle are as follows:
• DML locks: DML stands for Data Manipulation Language. In general this means
SELECT, INSERT, UPDATE, MERGE, and DELETE statements. DML locks are the
mechanism that allows for concurrent data modifications. DML locks will be, for
example, locks on a specific row of data or a lock at the table level that locks every
row in the table.
• DDL locks: DDL stands for Data Definition Language, (CREATE and ALTER
statements, and so on). DDL locks protect the definition of the structure of
objects.
• Internal locks and latches: Oracle uses these locks to protect its internal data
structures. For example, when Oracle parses a query and generates an optimized
query plan, it will latch the library cache to put that plan in there for other sessions
to use. A latch is a lightweight, low-level serialization device employed by Oracle,
similar in function to a lock. Do not confuse or be misled by the term lightweight;
latches are a common cause of contention in the database, as you will see. They
are lightweight in their implementation, but not their effect.
DML Locks
DML locks are used to ensure that only one person at a time modifies a row and that no one can drop a
table upon which you are working. Oracle will place these locks for you, more or less transparently, as
you do work.
TX (Transaction) Locks
In a database with a traditional memory-based lock manager, the process of locking a row would
resemble the following:
1. Find the address of the row you want to lock.
2. Get in line at the lock manager (which must be serialized, as it is a common in-
memory structure).
3. Lock the list.
4. Search through the list to see if anyone else has locked this row.
5. Create a new entry in the list to establish the fact that you have locked the row.
6. Unlock the list.
Now that you have the row locked, you can modify it. Later, as you commit your changes, you must continue the procedure as follows:
1. Get in line again.
2. Lock the list of locks.
3. Search through the list and release all of your locks.
4. Unlock the list
As you can see, the more locks acquired, the more time spent on this operation, both before and after modifying the data. Oracle does not do it that way. Oracle’s process looks like this:
1. Find the address of the row you want to lock.
2. Go to the row.
3. Lock the row right there, right then—at the location of the row, not in a big list somewhere (waiting for the transaction that has it locked to end if it is already locked, unless you are using the NOWAIT option).
In Chapter 10 “Database Tables”, we’ll get into the details of the block format, but suffice it to say that at the top of a database block is some leading overhead space in which to store a transaction table for that block. This transaction table contains an entry for each real transaction that has locked some data in that block. The size of this structure is controlled by two physical attribute parameters on the CREATE statement for an object:
• INITRANS: The initial, preallocated size of this structure. This defaults to 2 for indexes and tables.
• MAXTRANS: The maximum size to which this structure may grow. It defaults to 255 and has a minimum of 2 practically. In Oracle 10g and above, this setting has been deprecated, so it no longer applies. MAXTRANS is 255 regardless in that release and later.
Each block starts life with, by default, two transaction slots. The number of simultaneous active transactions that a block can ever have is constrained by the value of MAXTRANS and by the availability of space on the block. You may not be able to achieve 255 concurrent transactions on the block if there is
not sufficient space to grow this structure.
TM (DML Enqueue) Locks
TM locks are used to ensure that the structure of a table is not altered while you are modifying its
contents. For example, if you have updated a table, you will acquire a TM lock on that table. This will
prevent another user from executing DROP or ALTER commands on that table. If another user attempts
to perform DDL on the table while you have a TM lock on it, he’ll receive the following error message:
drop table dept
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified
DDL Locks
DDL locks are automatically placed against objects during a DDL operation to protect them from changes by other sessions. For example, if I perform the DDL operation ALTER TABLE T, the table T will in
general have an exclusive DDL lock placed against it, preventing other sessions from getting DDL locks
and TM locks on this table.There are three types of DDL locks:
• Exclusive DDL locks: These prevent other sessions from gaining a DDL lock or TM (DML) lock themselves. This means that you may query a table during a DDL operation, but you may not modify it in any way.
• Share DDL locks: These protect the structure of the referenced object against modification by other sessions, but allow modifications to the data.
• Breakable parse locks: These allow an object, such as a query plan cached in the shared pool, to register its reliance on some other object. If you perform DDL against that object, Oracle will review the list of objects that have registered their dependence and invalidate them. Hence, these locks are breakable—they do not prevent the DDL from occurring.
Latches
Latches are lightweight serialization devices used to coordinate multiuser access to shared data structures, objects, and files.
订阅:
博文 (Atom)