27,579
社区成员
发帖
与我相关
我的任务
分享
select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
你可以考虑不用游标,反正是2008,可以考虑用row_number函数,来变量表中的每一行数据,这样至少不会导致严重的阻塞问题,而且速度更快。
可以这样:
declare @i int;
declare @count int;
set @i = 1
set @count = (select count(*) from 表);
while @i <= @count
begin
;with t
as
(
select *,
row_number() over(order by @@servername) as rownum
from 表
)
select 你的变量1 = (select 字段 from 表 where rownum = @i),
你的变量2 = ...
--用变量构造动态语句
set @i = @i + 1
end
[/quote]
多谢大神。不过我看网上通过rownumber来遍历数据表很多采用了临时表,就是把查询数据放到临时表,再遍历临时表。这样是不是为了避免锁的问题。但是将数据插入临时表,再删除临时表又会减低一定的效率。[/quote]
哦 不会,临时表的开销很小的,如果数据较少,是直接放到内存中,的只有数据比较大的时候,才会放到硬盘上。
另外,临时表还支持创建索引。[/quote]
多谢。用临时表row_number代替游标进行遍历,减少了打开游标的阻塞问题。另外使用临时表会对系统表sysprocesses等进行加锁,所以有时候也可能导致阻塞,但是问题不大。目前我是使用了临时表变量。不过测试的时候发现还是存在一些超时已过期的问题。主要是在执行存储过程的时候,这个存储过程实现的功能就是构建插入语句插入到对应数据库中。但是在出现超时问题的时候查询阻塞情况,发现基本没有阻塞操作,或者阻塞的时间很短。出现超时的时候就会连续出现多次。还会有什么问题会导致这个存储过程超时呢。[/quote]
其实出现超时,一个是因为阻塞问题,另一个就是你语句的执行速度,由于你的语句大部分是插入操作,那么在插入大量数据的时候,是把数据插入到某一个数据页中的,一个页大小时8K,当这个页中的数据已经很多的时候,比如8K中,已经占用了7k了,那么这个时候再次插入多条记录,那么这个数据页可能就放不下这些记录了,于是sql server需要进行页分裂, 也就是page split,就是新增一个数据页,然后把原来的一页的内容,一般是平均分到这2页中,然后再把数据插入进去。
所以,这个时候可以考虑,先在数据页中,预留一部分空间,这个可以通过重建索引,然后指定fillfactor = 50,这样就可以让页中有一半是空闲空间,于是下次再次插入时,就会减少页的分裂。
随着插入的数据越来越多,这些页的填充程度,也越来越高,可能上升到80,那么这个时候,我们可以再次重建聚集索引,指定这个fillfactor = 50,于是数据再次重新分布。[/quote]
之前只是查看阻塞情况,忽视了对比效率。今天测试发现使用游标的效率比使用row_number高。使用游标的方式是open cursor for select ....... from table1,table2 where.......
而使用row_number的方式是将table1,table2的查询结果以及row_number存入临时表#temptable。然后通过
select @max = count(*) from #temptable
set @i = 1
while @i < @max
begin
select ....... from #temptable where rownum=@i
set @i = @i+1
end
通过这种方式进行遍历,发现效率比游标低很多,后来将#temptable的rownum设为主键,效率提高不少,但是还是比游标遍历低。
是不是我使用的方式有问题。
网上有人提到说row_number主要用产生顺序指令,http://social.msdn.microsoft.com/Forums/en-US/bb30f8ed-8ca3-448e-8f46-f55a7246b865/cursor-rownumber[/quote]
看了文章的连接,结合你的实际测试情况,看来用row_number的效率也不是太好。
要不帮你看看,你的存储过程到底是怎么写的,能不能优化吧,我加你关注了,可以发私信。select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
你可以考虑不用游标,反正是2008,可以考虑用row_number函数,来变量表中的每一行数据,这样至少不会导致严重的阻塞问题,而且速度更快。
可以这样:
declare @i int;
declare @count int;
set @i = 1
set @count = (select count(*) from 表);
while @i <= @count
begin
;with t
as
(
select *,
row_number() over(order by @@servername) as rownum
from 表
)
select 你的变量1 = (select 字段 from 表 where rownum = @i),
你的变量2 = ...
--用变量构造动态语句
set @i = @i + 1
end
[/quote]
多谢大神。不过我看网上通过rownumber来遍历数据表很多采用了临时表,就是把查询数据放到临时表,再遍历临时表。这样是不是为了避免锁的问题。但是将数据插入临时表,再删除临时表又会减低一定的效率。[/quote]
哦 不会,临时表的开销很小的,如果数据较少,是直接放到内存中,的只有数据比较大的时候,才会放到硬盘上。
另外,临时表还支持创建索引。[/quote]
多谢。用临时表row_number代替游标进行遍历,减少了打开游标的阻塞问题。另外使用临时表会对系统表sysprocesses等进行加锁,所以有时候也可能导致阻塞,但是问题不大。目前我是使用了临时表变量。不过测试的时候发现还是存在一些超时已过期的问题。主要是在执行存储过程的时候,这个存储过程实现的功能就是构建插入语句插入到对应数据库中。但是在出现超时问题的时候查询阻塞情况,发现基本没有阻塞操作,或者阻塞的时间很短。出现超时的时候就会连续出现多次。还会有什么问题会导致这个存储过程超时呢。[/quote]
其实出现超时,一个是因为阻塞问题,另一个就是你语句的执行速度,由于你的语句大部分是插入操作,那么在插入大量数据的时候,是把数据插入到某一个数据页中的,一个页大小时8K,当这个页中的数据已经很多的时候,比如8K中,已经占用了7k了,那么这个时候再次插入多条记录,那么这个数据页可能就放不下这些记录了,于是sql server需要进行页分裂, 也就是page split,就是新增一个数据页,然后把原来的一页的内容,一般是平均分到这2页中,然后再把数据插入进去。
所以,这个时候可以考虑,先在数据页中,预留一部分空间,这个可以通过重建索引,然后指定fillfactor = 50,这样就可以让页中有一半是空闲空间,于是下次再次插入时,就会减少页的分裂。
随着插入的数据越来越多,这些页的填充程度,也越来越高,可能上升到80,那么这个时候,我们可以再次重建聚集索引,指定这个fillfactor = 50,于是数据再次重新分布。[/quote]
之前只是查看阻塞情况,忽视了对比效率。今天测试发现使用游标的效率比使用row_number高。使用游标的方式是open cursor for select ....... from table1,table2 where.......
而使用row_number的方式是将table1,table2的查询结果以及row_number存入临时表#temptable。然后通过
select @max = count(*) from #temptable
set @i = 1
while @i < @max
begin
select ....... from #temptable where rownum=@i
set @i = @i+1
end
通过这种方式进行遍历,发现效率比游标低很多,后来将#temptable的rownum设为主键,效率提高不少,但是还是比游标遍历低。
是不是我使用的方式有问题。
网上有人提到说row_number主要用产生顺序指令,http://social.msdn.microsoft.com/Forums/en-US/bb30f8ed-8ca3-448e-8f46-f55a7246b865/cursor-rownumberselect *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
你可以考虑不用游标,反正是2008,可以考虑用row_number函数,来变量表中的每一行数据,这样至少不会导致严重的阻塞问题,而且速度更快。
可以这样:
declare @i int;
declare @count int;
set @i = 1
set @count = (select count(*) from 表);
while @i <= @count
begin
;with t
as
(
select *,
row_number() over(order by @@servername) as rownum
from 表
)
select 你的变量1 = (select 字段 from 表 where rownum = @i),
你的变量2 = ...
--用变量构造动态语句
set @i = @i + 1
end
[/quote]
多谢大神。不过我看网上通过rownumber来遍历数据表很多采用了临时表,就是把查询数据放到临时表,再遍历临时表。这样是不是为了避免锁的问题。但是将数据插入临时表,再删除临时表又会减低一定的效率。[/quote]
哦 不会,临时表的开销很小的,如果数据较少,是直接放到内存中,的只有数据比较大的时候,才会放到硬盘上。
另外,临时表还支持创建索引。[/quote]
多谢。用临时表row_number代替游标进行遍历,减少了打开游标的阻塞问题。另外使用临时表会对系统表sysprocesses等进行加锁,所以有时候也可能导致阻塞,但是问题不大。目前我是使用了临时表变量。不过测试的时候发现还是存在一些超时已过期的问题。主要是在执行存储过程的时候,这个存储过程实现的功能就是构建插入语句插入到对应数据库中。但是在出现超时问题的时候查询阻塞情况,发现基本没有阻塞操作,或者阻塞的时间很短。出现超时的时候就会连续出现多次。还会有什么问题会导致这个存储过程超时呢。[/quote]
其实出现超时,一个是因为阻塞问题,另一个就是你语句的执行速度,由于你的语句大部分是插入操作,那么在插入大量数据的时候,是把数据插入到某一个数据页中的,一个页大小时8K,当这个页中的数据已经很多的时候,比如8K中,已经占用了7k了,那么这个时候再次插入多条记录,那么这个数据页可能就放不下这些记录了,于是sql server需要进行页分裂, 也就是page split,就是新增一个数据页,然后把原来的一页的内容,一般是平均分到这2页中,然后再把数据插入进去。
所以,这个时候可以考虑,先在数据页中,预留一部分空间,这个可以通过重建索引,然后指定fillfactor = 50,这样就可以让页中有一半是空闲空间,于是下次再次插入时,就会减少页的分裂。
随着插入的数据越来越多,这些页的填充程度,也越来越高,可能上升到80,那么这个时候,我们可以再次重建聚集索引,指定这个fillfactor = 50,于是数据再次重新分布。select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
你可以考虑不用游标,反正是2008,可以考虑用row_number函数,来变量表中的每一行数据,这样至少不会导致严重的阻塞问题,而且速度更快。
可以这样:
declare @i int;
declare @count int;
set @i = 1
set @count = (select count(*) from 表);
while @i <= @count
begin
;with t
as
(
select *,
row_number() over(order by @@servername) as rownum
from 表
)
select 你的变量1 = (select 字段 from 表 where rownum = @i),
你的变量2 = ...
--用变量构造动态语句
set @i = @i + 1
end
[/quote]
多谢大神。不过我看网上通过rownumber来遍历数据表很多采用了临时表,就是把查询数据放到临时表,再遍历临时表。这样是不是为了避免锁的问题。但是将数据插入临时表,再删除临时表又会减低一定的效率。[/quote]
哦 不会,临时表的开销很小的,如果数据较少,是直接放到内存中,的只有数据比较大的时候,才会放到硬盘上。
另外,临时表还支持创建索引。[/quote]
多谢。用临时表row_number代替游标进行遍历,减少了打开游标的阻塞问题。另外使用临时表会对系统表sysprocesses等进行加锁,所以有时候也可能导致阻塞,但是问题不大。目前我是使用了临时表变量。不过测试的时候发现还是存在一些超时已过期的问题。主要是在执行存储过程的时候,这个存储过程实现的功能就是构建插入语句插入到对应数据库中。但是在出现超时问题的时候查询阻塞情况,发现基本没有阻塞操作,或者阻塞的时间很短。出现超时的时候就会连续出现多次。还会有什么问题会导致这个存储过程超时呢。select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
你可以考虑不用游标,反正是2008,可以考虑用row_number函数,来变量表中的每一行数据,这样至少不会导致严重的阻塞问题,而且速度更快。
可以这样:
declare @i int;
declare @count int;
set @i = 1
set @count = (select count(*) from 表);
while @i <= @count
begin
;with t
as
(
select *,
row_number() over(order by @@servername) as rownum
from 表
)
select 你的变量1 = (select 字段 from 表 where rownum = @i),
你的变量2 = ...
--用变量构造动态语句
set @i = @i + 1
end
select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。[/quote]
是的,游标不仅慢,而且可能锁住表的所有数据,造成严重的阻塞问题。select *
from sys.sysprocesses
where blocked <> 0
[/quote]
查到了,大部分是打开游标的阻塞。因为存储过程里面有一个操作是用游标遍历一个数据表的数据,构建sql语句。是不是游标会自动加锁。select *
from sys.sysprocesses
where blocked <> 0