sqlserver隔离级别
隔离级别用于决定并发事务如何读写数据的操作,同时对性能也有一定的影响作用,理解了事务隔离级别有助于理解事务的死锁。
如何确认隔离级别
- 确认当前会话的事务隔离级别(关注 isolation level)
DBCC USEROPTIONS
- SQL Server 支持以下几种隔离级别:
| 隔离级别 | 描述 | 备注 |
|---|---|---|
| READ UNCOMMITTED | 未提交读 | 不发出共享锁,允许读脏,相当于 WITH (NOLOCK) |
| READ COMMITTED | 已提交读 | 默认级别 |
| REPEATABLE READ | 可重复读 | 相当于 WITH (HOLDLOCK) |
| SNAPSHOT | 快照 | - |
| SERIALIZABLE | 可序列化 | 最高级别 |
注:隔离级别越高,读操作的请求锁定就越严格,锁的持有时间久越长;所以隔离级别越高,一致性就越高,并发性就越低,同时性能也相对影响越大。
如何设置隔离级别
会话级别
- 设置会话层面的隔离级别,示例
READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
查询表级别
- 通过锁提示设置查询表层面的隔离级别(锁提示会覆盖当前事务的隔离级别设置),示例如下:
--.不发出共享锁,允许脏读,可提高并发
SELECT * FROM xxx WITH (NOLOCK)
--.使用行锁锁定需要的行,而不是锁定整个页或表
UPDATE xxx WITH (ROWLOCK) SET name = 'abc' WHERE id = 1
--.其他事务可以读取表,但不能更新和删除,且只有该进程可以更新
SELECT * FROM xxx WITH (UPDLOCK)
--.其他事务不能读取表,也不能更新和删除
SELECT * FROM xxx WITH (TABLOCKX)
--.使用行级排他锁
SELECT * FROM xxx WITH (ROWLOCK, XLOCK) WHERE id = 1001
--.使用更新锁并保持到事务结束
SELECT * FROM xxx WITH (UPDLOCK, HOLDLOCK) WHERE Stock < 10
--.表级共享锁,防止其他事务修改表
SELECT * FROM xxx WITH (TABLOCK, HOLDLOCK)
| with锁提示 | 描述 | 备注 |
|---|---|---|
| NOLOCK | 不加锁 | 不发出共享锁,查询不受其它排他锁阻塞,相当于 READ UNCOMMITTED,只可用于select |
| HOLDLOCK | 保持锁 | 此锁保持至整个事务结束,不会在途中释放,相当于 SERIALIZABLE |
| UPDLOCK | 更新锁 | 读取数据将使用修改锁来代替共享锁, 其他事务可以读取表,但不能更新删除,只有该进程能修改数据 |
| ROWLOCK | 行锁 | 只锁定需要的行而不是整个页或表,以减少锁争用,适用于高并发环境下需要精确控制锁定的场景 |
| PAGLOCK | 页锁 | 使用共享页锁 |
| TABLOCK | 表锁 | 在整个表上置共享锁直至事务结束,保证其他进程只能读取而不能修改数据 |
| TABLOCKX | 排它表锁 | 在整个表上置排它表锁直至事务结束,在事务期间阻止任何其他事务读取或修改这张表 |
| XLOCK | 排他锁 | - |
注:正确使用锁提示可以提升安全、优化并发,但过度使用可能导致严重的并发问题
存储过程级别
- 在存储过程的开头使用
SET TRANSACTION ISOLATION LEVEL语句来设置隔离级别,示例READ COMMITTED
CREATE PROCEDURE xxx
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- 存储过程的代码
END
数据库级别
- 开启快照读:在保护事务不脏读未提交的数据修改的同时,尽量减少锁定争用(高并发推荐)
注:修改隔离级别需要关闭其他所有到该库的连接(并不要求设置单用户模式),但会造成阻塞而影响业务。
--.查询数据库状态
select name,snapshot_isolation_state,is_read_committed_snapshot_on from sys.databases
--.更改数据库为 快照隔离模式(乐观并发模型)
ALTER DATABASE [xxx] SET READ_COMMITTED_SNAPSHOT ON
ALTER DATABASE [xxx] SET ALLOW_SNAPSHOT_ISOLATION ON
--.查询数据库状态
select name,snapshot_isolation_state,is_read_committed_snapshot_on from sys.databases
- 延迟持久性:针对sql2014及以后版本,以丢数据的风险提高数据导入性能,可以提升磁盘io性能,特别是报表服务器(效果明显)
--.查看延迟持久性状态
select name,delayed_durability,delayed_durability_desc from sys.databases
--.更改延迟持久性
ALTER DATABASE [xxx] SET DELAYED_DURABILITY = ALLOWED WITH NO_WAIT
实例级别
- 不支持