有一些性能问题是由于对数据库锁的错误使用造成的。记得之前有个客户,alert中全是死锁的信息,最后发现原因是外键没有建立索引导致的。
1.基本概念
为了确保用户在存取同一数据库对象时的正确性(无丢失修改、可重复读、不读“脏”数据等),数据库引入了锁机制。基本的锁类型有两种:排它锁 X锁和共享锁 S锁。
排它锁
若事务T对数据D加X锁,则其他任何事务都不能再对D加任何类型的锁,直至T释放D上的X锁;一般要求在修改数据前向该数据加排它锁,所以排它锁有成为写锁。一个资源,比如一行或者一个表只能加一个排它锁,但是可以加多个共享锁。
共享锁
若事务T对数据D加S锁,则其他事务只能对D加S锁,而不能加X锁,直至T释放D上的S锁;一般要求读取数据前向该数据加共享锁,所以共享锁又称为读锁。
2.锁行为
锁作用于读取和写入的交互。读是对资源的查询,写是对资源的修改。以下列出了Oracle数据库对读和写的锁规则:
A row is locked only when modified by a writer.
行只有被写更改的时候锁定。
含义:当一个语句更新一行的时候,会话仅获得该行的锁。通过在行级别锁定数据,数据库最大程度的减少了对相同数据的争用。正常情况下,数据库不会把行锁升级为表锁。
A writer of a row blocks a concurrent writer of the same row.
对于行级别的修改阻止对相同行的并发修改。
含义:如果一个事务正在修改一行,行锁阻止其它的事务同时修改同一行。
A reader never blocks a writer.
读操作从来不会阻止写操作。
含义:因为读不会锁定,所以可以对该行做修改。除了SELECT … FOR UPDATE这个特殊的select语句。
A writer never blocks a reader.
写操作不会阻止读操作。
含义:当一行数据正在被修改,数据库使用UNDO提供给读一个该行的一致性视图。
pending distributed transactions
一个特殊情况就是挂起的分布式事务中,读操作可能需要等待对于相同数据块的写完成。
3.锁转换、锁升级、锁定时间
锁转换:Oracle根据需要执行锁转换。例如在SELECT … FOR UPDATE中,Oracle数据库自动将行共享锁转换为行排它锁。
锁升级:Oracle不会升级锁。例如Oracle不会将行锁升级为表锁。
锁定时间:Oracle在事务rollback或者commit或者rollback savepoint等之后,都会释放相应语句获得的锁,也就是在事务执行期间。但是有个特例就是:由于在外键没有建立索引子表的锁不是在事务期间,而是在语句执行期间。
4.死锁
死锁是两个或者多个用户等待彼此锁定的数据的一种情况。Oracle数据库自动检测死锁,并通过回滚死锁涉及的一条语句,释放一组冲突的行锁来解决死锁。数据库向进行语句级回滚的事务返回相应的消息,通常,此语句应该显式回滚。
记得有次电话面试,让我口头模拟一个死锁,知道是互相等待,两个会话就够了,但是最后说错了,回想起来,除了紧张,可能还是理解不够。
模拟两个会话产生死锁:
T | session1 | session2 |
---|---|---|
t0 | UPDATE employees set salary=salary*1.1 where employee_id=100; 1 row updated | UPDATE employees set salary=salary*1.1 where employee_id=200; 1 row updated |
t1 | UPDATE employees set salary=salary*1.1 where employee_id=200; no return | UPDATE employees set salary=salary*1.1 where employee_id=100; no return |
t2 | ORA-00060: deadlock detected while waiting for resource | |
t3 | commit; | |
t4 | 1 row updated. | |
t5 | commit; Commit complete. |
5.自动锁
Oracle数据库根据资源和要执行的操作自动获取不同类型的锁。
Lock | Description |
---|---|
DML Locks | Protect data. For example, table locks lock entire tables, while row locks lock selected rows. |
DDL Locks | Protect the structure of schema objects—for example, the dictionary definitions of tables and views. |
System Locks | Protect internal database structures such as data files. Latches, mutexes, and internal locks are entirely automatic. |
DML锁,也称为数据锁,保证多个用户并发访问的数据的完整性。DML语句自动获取TX锁和TM锁,即行锁与表锁。
5.1.DML–ROW Locks(TX)
行锁,也称为TX锁。事务为每一行请求行锁,当执行insert、update、delete、merge、select … for update,直至会话commit或者rollback之后行锁释放。
有一些锁,如果我们不知道具体含义的话,可以通过数据字典查看,之前记得碰到TO锁,第一时间也是不知道啥含义。
SQL> set serveroutput on
SQL> exec print_table('select * from v$lock_type where type=''TX''');
TYPE : TX
NAME : Transaction
ID1_TAG : usn<<16 | slot
ID2_TAG : sequence
IS_USER : YES
DESCRIPTION : Lock held by a transaction to allow other
transactions to wait for it
-----------------
PL/SQL procedure successfully completed.
SQL>
SQL> exec print_table('select * from v$lock_type where type=''TO''');
TYPE : TO
NAME : Temp Object
ID1_TAG : object #
ID2_TAG : 1
IS_USER : NO
DESCRIPTION : Synchronizes DDL and DML operations on a temp
object
-----------------
PL/SQL procedure successfully completed
--以上pring_table引用了一个脚本,是《Oracle性能优化与诊断案例精选》里面看到的
create or replace procedure print_table( p_query in varchar2 )
AUTHID CURRENT_USER
is
l_theCursor integer default dbms_SQL.open_cursor;
l_columnValue varchar2(4000);
l_status integer;
l_descTbl dbms_SQL.desc_tab;
l_colCnt number;
begin
execute immediate
'alter session set
nls_date_format=''dd-mon-yyyy hh24:mi:ss'' ';
dbms_SQL.parse( l_theCursor, p_query, dbms_SQL.native );
dbms_SQL.describe_columns
( l_theCursor, l_colCnt, l_descTbl );
for i in 1 .. l_colCnt loop
dbms_SQL.define_column
(l_theCursor, i, l_columnValue, 4000);
end loop;
l_status := dbms_SQL.execute(l_theCursor);
while ( dbms_SQL.fetch_rows(l_theCursor) > 0 ) loop
for i in 1 .. l_colCnt loop
dbms_SQL.column_value
( l_theCursor, i, l_columnValue );
dbms_output.put_line
( rpad( l_descTbl(i).col_name, 30 )
|| ': ' ||
l_columnValue );
end loop;
dbms_output.put_line( '-----------------' );
end loop;
execute immediate
'alter session set nls_date_format=''dd-MON-rr'' ';
exception
when others then
execute immediate
'alter session set nls_date_format=''dd-MON-rr'' ';
raise;
end;
/
复制
那TX锁我们怎么查呢,参考这里
-------------------------------小节分割线-----------------------------------
文章被以下合辑收录
评论
