本篇文章主要介绍 SqlServer 使用时的注意事项.
想成为一个高级程序员, 数据库的使用是必须要会的. 而数据库的使用纯熟程度, 也侧面反映了一个开放的水平.
下面介绍 SqlServer 在使用和设计的过程中需要注意的事项.
SqlServer 注意事项
Sql 事务启动语句
开始事务: BEGIN TRANSACTION
提交事务: COMMIT TRANSACTION
回滚事务: ROLLBACK TRANSACTION
相关注意事项
保持事务简短, 事务越短, 越不可能造成阻塞.
在事务中尽量避免使用循环 while 和游标, 以及避免采用访问大量行的语句.
事务中不要要求用户输入.
在启动事务前完成所有的计算和查询等操作.
避免同一事务中交错读取和更新. 可以使用表变量预先存储数据. 即存储过程中查询与更新使用两个事务实现.
超时会让事务不执行回滚, 超时后如果客户端关闭连接 sqlserver 自动回滚事务. 如果不关闭, 将造成数据丢失, 而其他事务将在这个未关闭的连接上执行, 造成资源锁定, 甚至服务器停止响应.
避免超时后还可打开事务 SET XACT_ABORT ON 统计信息可以优化查询速度, 统计信息准确可以避免查询扫描, 直接进行索引查找.
sp_updatestats 可以更新统计信息到最新.
低内存会导致未被客户端连接的查询计划被清除.
修改表结构, 修改索引后, 查询计划会被清除, 可以再修改后运行几遍查询.
DDL DML 交错和查询内部 SET 选项将重新编译查询计划.
order by 影响查询速度.
where 中使用函数则会调用筛选器进行扫描, 扫描表要尽量避免.
updlock 和 holdlock 同时使用可以在早期锁定后面需要更新的资源, 维护资源完整性, 避免冲突.
如果不需要使用临时表的统计信息来进行大数据查询, 表变量是更好的选择.
事务使用注意事项
设置事务隔离级别 (未提交读, 读脏), 相当于 (NOLOCK) 的语句:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
隔离级别描述如下:
1.READ UNCOMMITTED
READ UNCOMMITTED: 未提交读, 读脏数据.
默认的读操作: 需要请求共享锁, 允许其他事物读锁定的数据但不允许修改.
READ UNCOMMITTED: 读操作不申请锁, 运行读取未提交的修改, 也就是允许读脏数据, 读操作不会影响写操作请求排他锁.
2.READ COMMITTED
READ COMMITTED(已提交读) 是 SQL SERVER 默认的隔离级别, 可以避免读取未提交的数据, 隔离级别比 READ UNCOMMITTED 未提交读的级别更高;
该隔离级别读操作之前首先申请并获得共享锁, 允许其他读操作读取该锁定的数据, 但是写操作必须等待锁释放, 一般读操作读取完就会立刻释放共享锁.
3.REPEATABLE READ
REPEATABLE READ(可重复读): 保证在一个事务中的两个读操作之间, 其他的事务不能修改当前事务读取的数据, 该级别事务获取数据前必须先获得共享锁同时获得的共享锁不立即释放一直保持共享锁至事务完成, 所以此隔离级别查询完并提交事务很重要.
4.SERIALIZABLE
SERIALIZABLE(可序列化), 对于前面的 REPEATABLE READ 能保证事务可重复读, 但是事务只锁定查询第一次运行时获取的数据资源 (数据行), 而不能锁定查询结果之外的行, 就是原本不存在于数据表中的数据. 因此在一个事务中当第一个查询和第二个查询过程之间, 有其他事务执行插入操作且插入数据满足第一次查询读取过滤的条件时, 那么在第二次查询的结果中就会存在这些新插入的数据, 使两次查询结果不一致, 这种读操作称之为幻读.
为了避免幻读需要将隔离级别设置为 SERIALIZABLE
5.SNAPSHOT
SNAPSHOT 快照: SNAPSHOT 和 READ COMMITTED SNAPSHOT 两种隔离 (可以把事务已经提交的行的上一版本保存在 TEMPDB 数据库中)
SNAPSHOT 隔离级别在逻辑上与 SERIALIZABLE 类似
READ COMMITTED SNAPSHOT 隔离级别在逻辑上与 READ COMMITTED 类似
不过在快照隔离级别下读操作不需要申请获得共享锁, 所以即便是数据已经存在排他锁也不影响读操作. 而且仍然可以得到和 SERIALIZABLE 与 READ COMMITTED 隔离级别类似的一致性; 如果目前版本与预期的版本不一致, 读操作可以从 TEMPDB 中获取预期的版本.
如果启用任何一种基于快照的隔离级别, DELETE 和 UPDATE 语句在做出修改前都会把行的当前版本复制到 TEMPDB 中, 而 INSERT 语句不需要在 TEMPDB 中进行版本控制, 因为此时还没有行的旧数据
无论启用哪种基于快照的隔离级别都会对更新和删除操作产生性能的负面影响, 但是有利于提高读操作的性能因为读操作不需要获取共享锁;
5.1SNAPSHOT
SNAPSHOT 在 SNAPSHOT 隔离级别下, 当读取数据时可以保证操作读取的行是事务开始时可用的最后提交版本
同时 SNAPSHOT 隔离级别也满足前面的已提交读, 可重复读, 不幻读; 该隔离级别实用的不是共享锁, 而是行版本控制
使用 SNAPSHOT 隔离级别首先需要在数据库级别上设置相关选项
5.2READ COMMITTED SNAPSHOT
READ COMMITTED SNAPSHOT 也是基于行版本控制, 但是 READ COMMITTED SNAPSHOT 的隔离级别是读操作之前的最后已提交版本, 而不是事务前的已提交版本, 有点类似前面的 READ COMMITTED 能保证已提交读, 但是不能保证可重复读, 不能避免幻读, 但是又比 READ COMMITTED 隔离级别多出了不需要获取共享锁就可以读取数据
SqlServer[锁] 注意事项
一, 页锁实例
- T1: select * from table (paglock)
- T2: update table set column1='hello' where id>10
说明
T1 执行时, 会先对第一页加锁, 读完第一页后, 释放锁, 再对第二页加锁, 依此类推. 假设前 10 行记录恰好是一页 (当然, 一般不可能一页只有 10 行记录), 那么 T1 执行到第一页查询时, 并不会阻塞 T2 的更新.
----------------------------------------------------------------------------------------------------
二, 行锁实例
- T1: select * from table (rowlock)
- T2: update table set column1='hello' where id=10
说明
T1 执行时, 对每行加共享锁, 读取, 然后释放, 再对下一行加锁; T2 执行时, 会对 id=10 的那一行试图加锁, 只要该行没有被 T1 加上行锁, T2 就可以顺利执行 update 操作.
----------------------------------------------------------------------------------------------------
三, 整表锁实例
- T1: select * from table (tablock)
- T2: update table set column1='hello' where id = 10
说明
T1 执行, 对整个表加共享锁. T1 必须完全查询完, T2 才可以允许加锁, 并开始更新.
----------------------------------------------------------------------------------------------------
婚前最后一篇博文, 希望婚后的自己还能坚持更新.
----------------------------------------------------------------------------------------------------
来源: https://www.cnblogs.com/kiba/p/9351119.html