0
点赞
收藏
分享

微信扫一扫

SqlServer性能优化 提高并发性能二(九)

 

    补充上一篇修改用非聚集索引:

update Employee set age=age+1 from Employee with(index=nc_Employee_Age) where age<30

 执行计划:

SqlServer性能优化 提高并发性能二(九)_数据库

并发访问控制隔离级别:

       1.读提交:默认行为,读取时请求S锁

set transaction isolation level read committed
select * from Employee where age=34

       2.   脏读:读取时不请求S锁,不会受到其他X锁限制

set transaction isolation level read uncommitted
select * from Employee

       3. 已提交快照读:更新时将老的数据复制到 Tempdb:read_committed_snapshot

alter database HRDB
set read_committed_snapshot on

 

设置成单用户模式:

SqlServer性能优化 提高并发性能二(九)_隔离级别_02

        设置事物:

begin tran
update Employee set age=age+1 where age>=30

   执行语句:

select * from Employee

 

SqlServer性能优化 提高并发性能二(九)_数据_03

这条语句也可以执行:

select * from Employee where age>30

 这条可以执行:

update Employee set age=age+1 from Employee with(index=nc_Employee_Age) where age<30

没有复制的还是从索引或基表中读取。所以可以读取出数据 

这条不能执行:

update Employee set age=age+1 from Employee with(index=nc_Employee_Age) where age>30

 打开数据库的读提交快照。 对记录进行操作时,会把排他锁的数据放到Tempdb数据库中,访问的时候直接读出Tempdb的数据。

       4.可重复读:事物结束前,不释放获取的S锁,可能会形成死锁

create table Products(id int identity(1,1),name varchar(500),UnitPrice money)

delete from Products where id=2
insert Products values ('p1',13)
insert Products values('p2',5)

--业务逻辑:单价大于10的优惠10
begin tran
declare @UnitPrice money
set @UnitPrice=(select @UnitPrice from Products where id=1)

--执行等待的时间
waitfor delay '00:00:20'
if @UnitPrice>10
update Products set UnitPrice=UnitPrice-10 where id=1
commit tran

 第二个人执行打六折的业务:

update Products set UnitPrice=UnitPrice*0.6

 结果:

SqlServer性能优化 提高并发性能二(九)_数据库_04

事务中尽量不要放查询语句:13*0.6=7.8      7.8-10=-2.2

实在要查询语句,如何解决呢?

删除上述表:drop table Products   重新创建

1. --在开启事务之前  设置事务的级别  可重复读

--在开启事务之前  设置事务的级别  可重复读
set transaction isolation level repeatable read
--业务逻辑:单价大于10的优惠10
begin tran
declare @UnitPrice money
set @UnitPrice=(select @UnitPrice from Products where id=1)

--执行等待的时间
waitfor delay '00:00:20'
if @UnitPrice>10
update Products set UnitPrice=UnitPrice-10 where id=1
commit tran

 2.打六折:

update Products set UnitPrice=UnitPrice*0.6

 结果:

SqlServer性能优化 提高并发性能二(九)_数据库_05

with(updlock) 可重复读的方式 可以保护线程。代码如下:

begin tran 
declare @UnitPrice money
set @UnitPrice=(select @UnitPrice from Products with(updlock) where id=1)

--执行等待的时间
waitfor delay '00:00:20'
if @UnitPrice>10
update Products set UnitPrice=UnitPrice-10 where id=1
commit tran

update Products set UnitPrice=UnitPrice*0.6

 

SqlServer性能优化 提高并发性能二(九)_数据_06

       5. 串行化:访问的行和按顺序下一行放置范围锁,防止不必要操作与插入数据

业务背景:给分组为:‘group1’的员工发奖金,加入了新的员工

create table Employees(id int identity(1,1),name varchar(500),groups varchar(500),salary money)
insert Employees values('caojian','grouup1',3000)
insert Employees values('ligang','grouup1',1000)
insert Employees values('huang','grouup2',1500)
insert Employees values('sunliyuan','grouup2',2000)

 业务逻辑的事务语句:

begin tran
declare @count int
set @count=(select COUNT(*) from Employees where groups='grouup1')
declare @avgsalary money
set @avgsalary=20000/@count

waitfor delay '00:00:20'
update Employees set salary=salary+@avgsalary where groups='grouup1'
commit tran

 第二个线程执行的语句:

insert Employees values ('newemployee','grouup1',0)

  这种结果是不对的:

SqlServer性能优化 提高并发性能二(九)_数据_07

   --设置串行化

set transaction isolation level  serializable
begin tran
declare @count int
set @count=(select COUNT(*) from Employees where groups='grouup1')
declare @avgsalary money
set @avgsalary=20000/@count

waitfor delay '00:00:20'
update Employees set salary=salary+@avgsalary where groups='grouup1'
commit tran

 进行添加:

insert Employees values ('newemployee','grouup1',0)

 执行查询语句:

SqlServer性能优化 提高并发性能二(九)_隔离级别_08

针对group创建索引:

--针对group创建聚集索引
create clustered index c_Employees_group on Employees (groups)

 执行事务:

--设置串行化
set transaction isolation level serializable
begin tran
declare @count int
set @count=(select COUNT(*) from Employees where groups='grouup1')
declare @avgsalary money
set @avgsalary=20000/@count

waitfor delay '00:00:20'
update Employees set salary=salary+@avgsalary where groups='grouup1'
commit tran

 执行以下三条语句:

insert Employees values ('newemployee','grouup1',0)
insert Employees values ('newemployee','grouup2',0)
insert Employees values ('newemployee','grouup3',0)

 grouup1有影响,grouup2和grouup3无影响。

SqlServer性能优化 提高并发性能二(九)_数据库_09

 

       6. 快照:比已提交快照读取更严格,试图对修改数据应用X(排他锁),如果已发生改变,事物失败 allow_snapshot_isolation

   创建表:

create table SnapShotTB(id int identity(1,1),name varchar(500),age int)
insert SnapShotTB values('caojian',33)

 给数据库进行配置:

--打开配置数据库的一个选项
alter database HRDB
--允许快照隔离
set allow_snapshot_isolation on

 设置事物的隔离级别:

--设置事物的隔离级别为快照
set transaction isolation level snapshot
begin transaction
declare @age int
set @age=(select age from SnapShotTB where name='caojian')
waitfor delay '00:00:20'
update SnapShotTB set age =age+1 where name='caojian'
commit tran

 第二个线程:

update SnapShotTB set age =age-1 where name='caojian'

 报的错误:

SqlServer性能优化 提高并发性能二(九)_隔离级别_10

减少阻塞与死锁的建议:

   1.合适的索引

   2.合适的分区

   3.调整合适的隔离级别

   4.查询条件的有限性

   5.相同的顺序操作资源

   6.短的事务

 

.NET 调用的案例:(EF CodeFirst)

    1.连上数据库。

    2.引入命名空间。

SqlServer性能优化 提高并发性能二(九)_数据_11

   3.在领域层引入命名空间:

using System.Transactions;
using System.Data;
using System.Linq;

 4.代码:

/// <summary>
/// 奖金处理的业务
/// </summary>
public void ProcessSalary()
{
TransactionOptions option = new TransactionOptions();
//指定的隔离级别(串行化)
option.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using (TransactionScope scope=new TransactionScope(TransactionScopeOption.Required,option))
{
//连到数据访问的上下文
HRUser dbcontext = new HRUser();
var employees = dbcontext.Set<Employees>().Where(p => p.groups == "grouup1").ToList();
//取得groupp1组的人数
int count = employees.Count;
//把奖金进行employees平分
decimal salary = 20000 / count;
//对每个人的值进行跟新
foreach (var emoloyee in employees)
{
dbcontext.Set<Employees>().Attach(emoloyee);
//状态是可修改的
dbcontext.Entry<Employees>(emoloyee).State = System.Data.Entity.EntityState.Modified;
emoloyee.salary = emoloyee.salary + salary;
}
dbcontext.SaveChanges();
//事物的完成
scope.Complete();
}
}

 调用:

protected void Button1_Click(object sender, EventArgs e)
{
Employees es = new Employees();
es.ProcessSalary();
}

 点击button数据库更新成功。

       7. 索引对隔离级别的影响、阻塞的监视

 



举报

相关推荐

0 条评论