游标的使用

  • Post author:
  • Post category:其他


昨天在SQL Server版面上遇到了这样的一个问题:

有一个表如下:

CREATE TABLE [#tmp](px int IDENTITY(1,1),value int)

大约有10000条记录,value 字段是一个随机的值,现要求是输入的一个值M,要找出前N条记录,且N条记录value的总和刚好不大M(意思是再多一条记录都会大于M)。

要求:语句运行时间要求在1秒种内完成

说明:

px值小的认为是排在px大的前面,可以用存领储过程、函数

示例数据为:

px   value

———-

5    5

4    12

7    9

1    3

3    6

6    23

2    15

则,录入20,找出:

px   value

———-

1    3

2    15


1、

最初打算用最常规的方法来实现这个需求,但是不考虑效率方面的要求:

select a.* from #tmp a where (select sum(value) from #tmp where px<=a.px)<

=@m

结果在10,000条测试数据的压力测试下,整个查询历时41s,与效率要求相去甚远


2、

于是,转而通过遍历表的方式实现查询:

declare @px int,@s bigint,@m int

set @s=0

set @m=20

update a

set

@px=case when @s<

=@m

then px else @px end,

@s

=@s+value


from

#t1 a

select * from #t1 where px<@px order by px

在100,000条测试数据的情况下,效率基本满意,但是又出现了新的问题,一旦px字段不是按升序排列,查询的结果就不正确

3、

与pbsql(风云)君子所见略同,决定用游标

declare @px int,@value int,@sum int,@m int,@px1 int

set @sum=0

set @m=20

declare t_cursor cursor for select px,value from #tmp order by px

open t_cursor

fetch next from t_cursor into @px,@value

while @@fetch_status=0

begin

if(@sum>@m)

break

set @sum=@sum+@value

set @px1=@px

fetch next from t_cursor into @px,@value

end

close t_cursor

deallocate t_cursor

select * from #tmp where px<@px1 order by px

效率可以到达要求,原以为万事大吉,结果提问者认为游标慢,要求不用游标

4、

最后,好汉只能下猛料了

declare @px int,@s int,@m int

set @s=0

set @m=20

select

@px=case when @s<

=@m

then px else @px end,

@s

=@s+case

when @s<

=@m

then value else 0 end

from

(select top 100 percent * from #tmp order by px) a

select * from #tmp where px<@px order by px


总结:

1、对于某些特殊的查询,不能单纯为了图SQL语句简单直观,不能认为简单就效率高,简单就是美,其实查询不是那么简单

2、不要固执的认为游标慢,当然,在与select * from tab where …等诸多情况比较,游标遍历表确实是效率低一些,然而有些时候,游标的效率不是我们想象中那么差劲的,就比如这

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=566908