翻动100万级的数据 —— 只需几十毫秒 之揭秘篇:有详细的说明,不要错过。
http://community.csdn.net/Expert/TopicView3.asp?id=4180563
http://www.jyklzz.com/bbs/ 演示页面
感谢大家的支持!!!
昨天发了一个邀请,邀请大家帮忙测试,效果还可以,下面小结一下:
通过内部的计数器得知:访问次数是1071(其中有好多是自己点的:)),人数不是太理想,本来是想看看上万人同时访问的情况:)
系统资源的占用情况
内存 —— 很理想。SQL占用的内存最大也没有超过65M,一般是在35M左右;asp.net占用的内存最大也没有超过40M,一般是在25M左右。
CPU:8%左右,由于访问次数不多,也不够集中,所以这个数值也说明不了什么。自己连续点了n次下一页,发现CPU的使用率飘高,达到了50%左右。
但是对于100万的记录,AMD XP2000+ 的CPU 几十毫秒的放映速度,因该是可以接受的,甚至是很理想的吧。
毕竟服务器的CPU要比我的快很多吧,而且记录也很难达到100万吧。
结果还是很满意的,但是美中不足的是,我想看一下海量访问的情况下的效果,
希望大家再支持一下,多点几下,谢谢了。呵呵
另外说明一下:前n页可以在60毫秒内完成,n应该是大于500的,小于多少嘛还没有测试。后n页就比较慢了,需要500毫秒左右。
下面讨论一下翻页的技巧吧。
我没有用游标、临时表、not in、in 这些方法,并不是说他们的效率不高,而是我还没有测试过。我只用了 top ,查了两次表。
大家也可提供一些其他的方法,我来测试一下,看看在100万条的情况下的效果。(请不要给在存储过程里面组串的,看着实在是太费劲了)
问题点数:20、回复次数:154Top
1 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 08:09:42 得分 0
讨论的前提是在海量数据的情况下,至少是在10万以上的。如果是很少的数据呢,那怎么翻都可以了。也差不了多少。
1.设置合理的索引
首先要做的是设置合理的索引,这个好像经常被忽略,至少很少被谈起。
注意:主键是索引的一种,而且是最快的一种。如果你都是把组件当作排序字段的话,那么你已经利用了索引。
不设置合理的所引的话,会导致查询速度非常的慢,甚至会造成超时。
这方面你可以做一个实验:找一个表,填进去10万条记录,假设有ID 、addedDate等字段,在查询分析器里面执行一下
select top 10 * from table
应该立刻就能出现结果。
然后再执行 select top 10 * from table order by ID(这时ID字段是主键)
也是立刻就出现了结果。
然后再执行 select top 10 * from table order by addedDate (这时addedDate字段没有索引)
你会发现速度很慢。
现在给addedDate 加一个非聚集索引,然后在执行上面的查询语句,速度也变得很快了。
可见索引神奇的效果!
这是翻动百万级记录最基本的设置,具体到我的那个论坛的翻页,我是设置了BoardID、 replyDate两个字段作为联合索引的。
因为是要在同一个讨论组李翻页,而且是按replyDate排序的。
2.只返回需要的记录
对于海量数据,都读出来做缓存,那是不可想象的(记录少的话,也要看利用率,一般都是很浪费的)。
所以呢如果一页显示20条的话名那就只都读出来20条,这样就很省内存和时间。
注意:虽然ADO.NET里面有这个方法
SqlDataAdapter.Fill(DataSet1,startRecord,maxRecords,srcTable);
但是他还是要先从SQL里面把查询语句的查出来的所有记录都出来,然后在截取指定的记录数。这对于SQL来说是一样的,对于海量数据依然会很慢。
论坛里的首页用的是select top 20 * from table where boardID = 5 order by replyDate desc
这样呢就只返回了20条记录,再加上索引的功劳,速度是非常快的。
Top
2 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 08:10:31 得分 0
3.尽量减少字段的长度
一个表可以建很多的字段,但是字段的总长度不能超过8060B,也就是说如果你建了一个char(8060)的字段,就不能在建其他的字段了。
我在第一次的测试中(星期天的),把主题的所有信息都放在了一个表里面,包括了一个nvarchar(3600)的主题内容的字段,复制记录的时候发现非常的慢,
当达到9万的时候,就已经很慢的,勉强把记录数拷贝到了35万,加了索引,测试了一下,翻页速度还是可以的,前n也都是很快的,后n页就很慢了,
如果再加上查询那就非常之慢了。
查看了一下数据文件吓了一跳 —— 他居然占用了1.4G的硬盘空间,怪不得拷贝和查询都慢的要死呢。
于是修改了一下表结构,把那个nvarchar(3600)的主题内容的字段踢了出去,放在一个单独的表里面。
再重新拷贝记录就非常的快了,很快就把记录数从16表成了1048577。昨天的测试就是在这个条件下进行的。
4.技巧
终于到了翻页算法的地方了,呵呵没有等急吧。
思路呢就是先找到一个标志,然后呢把大于(或小于)这个标志的前n条记录取出来。
什么?没看懂。没关系,我举个例子吧。
假设是按ID倒序的,每一页显示10条记录,有100条记录,记录号正好是1到100(怎么这么巧??为了说明方便嘛)
那么第一页的记录就是100到91、第二页的记录就是90到81、第三页的记录就是80到71......
我现在要翻到第三页,那么要找到第21行的记录的ID的值(也就是80),然后把小于等于80的记录用top 10 取出来就行了。
查询语句
declare @pageSize int --返回一页的记录数
declare @CurPage int --页号(第几页)1:第一页;2:第二页;......;-1最后一页。
declare @Count int
declare @id int
set @pageSize=10
set @CurPage =1
if @CurPage = -1
begin
--最后一页
set rowcount @pageSize
select @id=ID from table order by ID
end
--定位
if @CurPage > 0
begin
set @Count = @pageSize * (@CurPage -1) + 1
set rowcount @Count
select @id=ID from table order by ID desc
end
--返回记录
set rowcount @pageSize
select * from table where ID <=@id order by ID desc
set rowcount 0
其中“定位”用了 select @id=ID from table order by ID desc
这种方法,感觉上是很省内存的,因为只记录了一个ID,
然后用 select * from table where ID <=@id order by ID desc
取得最终需要的记录
set rowcount @pageSize 相当于 top @pageSize 。
优点:无论翻到哪一页,内存的占用情况都不变,多人访问内存也不会不变,很多人呢,还没有测试出来:)
缺点:单表、单排序字段。Top
3 楼laohuchiren(桌子凳子)回复于 2005-08-02 08:19:41 得分 1
学习Top
4 楼fanweiwei(黑暗凝聚力量,堕落方能自由)回复于 2005-08-02 08:22:46 得分 1
upTop
5 楼molti(八极狂侍)回复于 2005-08-02 08:25:32 得分 1
翻页那里我现在用的DataGrid自定义分页,可能性能远不如此Top
6 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 08:25:38 得分 0
http://community.csdn.net/Expert/TopicView3.asp?id=4180563
这里还有很多分Top
7 楼leo2003(【健者天行】谁伴我闯荡)回复于 2005-08-02 08:26:59 得分 1
学习Top
8 楼flashasp(flashasp)回复于 2005-08-02 08:28:38 得分 1
学习一把Top
9 楼bomberwu(贝克)回复于 2005-08-02 08:30:04 得分 1
看了还是有收获Top
10 楼flashasp(flashasp)回复于 2005-08-02 08:31:48 得分 1
不过我这里执行时间有时候是47毫秒Top
11 楼hipop(不怕慢,就怕站;站一站,二里半)回复于 2005-08-02 08:32:16 得分 1
学习!Top
12 楼lovebanyi(风云)回复于 2005-08-02 08:34:28 得分 1
不错啊。Top
13 楼wen98091(雪)回复于 2005-08-02 08:34:54 得分 1
study
Top
14 楼iuhxq(小灰)回复于 2005-08-02 08:35:09 得分 1
麻烦楼主测试一下这个存储过程,看速度如何?
愿意一起讨论分页
CREATE proc page
@RecordCount int output,
@QueryStr nvarchar(100)='table1',--表名、视图名、查询语句
@PageSize int=20, --每页的大小(行数)
@PageCurrent int=2, --要显示的页 从0开始
@FdShow nvarchar (1000)='*', --要显示的字段列表
@IdentityStr nvarchar (100)='id', --主键
@WhereStr nvarchar (200)='1=1',
@FdOrder nvarchar(100)='desc' --排序 只能取desc或者asc
as
--by quxh 2005.7.19
declare
@sql nvarchar(2000)
set @WhereStr = replace(@WhereStr, ';', '')
set @WhereStr = replace(UPPER(@WhereStr), 'DELETE', '')
set @WhereStr = replace(@WhereStr, 'DROP', '')
set @WhereStr = replace(@WhereStr, 'UPDATE', '')
set @WhereStr = replace(@WhereStr, 'FROM', '')
set @WhereStr = replace(@WhereStr, '--', '')
set @WhereStr = replace(@WhereStr, 'EXECUTE', '')
if @WhereStr = '' begin
set @WhereStr = '1=1'
end
if @PageCurrent = 0 begin
set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' order by ' + @IdentityStr + ' ' + @FdOrder
end
else begin
if upper(@FdOrder) = 'DESC' begin
set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' and ' + @IdentityStr + '< ( select min(' + @IdentityStr + ') from (select top ' + cast(@PageSize*@PageCurrent as nvarchar(10)) + ' ' + @IdentityStr + ' from ' + @QueryStr + ' where ' + @WhereStr + ' order by ' + @IdentityStr + ' desc) as t) order by ' + @IdentityStr + ' desc'
end
else begin
set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' and ' + @IdentityStr + '> ( select max(' + @IdentityStr + ') from (select top ' + cast(@PageSize*@PageCurrent as nvarchar(10)) + ' ' + @IdentityStr + ' from ' + @QueryStr + ' where ' + @WhereStr + ' order by ' + @IdentityStr + ' asc) as t) order by ' + @IdentityStr + ' asc'
end
end
--print @sql
execute(@sql)
if(@RecordCount is null or @RecordCount<0)begin
declare @tsql nvarchar(200)
set @tsql=N'select @RecordCount = count(*) from ' + @QueryStr + ' where ' + @WhereStr
exec sp_executesql @tsql,N'@RecordCount int output',@RecordCount output
select @RecordCount--这行没什么用处,可以不加
end
GO
Top
15 楼iuhxq(小灰)回复于 2005-08-02 08:35:56 得分 1
也是用的top实现的,还有,上面的过滤好象没有什么用,因为ADO.NET似乎可以处理这些安全问题Top
16 楼beijinboy(国产老顽童)回复于 2005-08-02 08:37:17 得分 1
gzTop
17 楼iuhxq(小灰)回复于 2005-08-02 08:38:28 得分 1
不好意思,楼主,才看到这句话:(请不要给在存储过程里面组串的,看着实在是太费劲了)
你可以不用看实现过程呢,就是测试一下速度就行
调用方式:
CREATE proc Bmhd_News_GetNewsetByKindAndField
@kindid int,
@recordcount int out,
@PageSize int=20,
@PageIndex int=0,
@field nvarchar (40)
as
declare @wherestr nvarchar(400)
set @wherestr = 'kindid = ' + str(@kindid) +' and field = ' + str(@field)
exec page @recordcount out,'News',@PageSize,@PageIndex,'*','id',@wherestr,'desc'
return 0
GO
Top
18 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 08:39:44 得分 0
对了,忘了最重要的一点 —— count(*)
翻页的时候没有用count(*)因为他会很占用内存的,也会很占用时间。
帖子的总数是记录在另一个表里的,用的时候去一下就行了
Top
19 楼yuekai(BTS)回复于 2005-08-02 08:43:04 得分 1
论坛删除帖子也是很常见的,如果中间包含删除的帖子,ID就会不连续,这个怎么办?Top
20 楼xu770(我爱鱼儿)回复于 2005-08-02 08:43:05 得分 1
学习Top
21 楼xu770(我爱鱼儿)回复于 2005-08-02 08:43:50 得分 1
学习Top
22 楼chx_xuxu(逍遥客)回复于 2005-08-02 08:45:24 得分 1
学习Top
23 楼liuqinglq(白菜)回复于 2005-08-02 08:46:26 得分 1
标记...又是分页啊Top
24 楼Haoye(haoye)回复于 2005-08-02 08:52:18 得分 1
如果要结合多个字段进行排序呢?如时间等Top
25 楼wufeng0524(高处不胜寒)回复于 2005-08-02 08:57:38 得分 0
先谢,回头测试!
__________________________________________
DotNet中华网:www.aspxcn.orgTop
26 楼icedut(冰-装修进行中)回复于 2005-08-02 09:03:52 得分 0
留个记号
有空时好好看看Top
27 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 09:06:26 得分 0
to:yuekai(tiger)
只是为了方便说明,其实ID不连续采这么费劲呢,如果是连续的那就简单多了呀。
论坛按回复事件排序的
to:iuhxq
已经找出来了,你的方法是:
select top 20 * from table1
where 1=1 and id <
( select min(id) from (select top 40 id from table1 where 1=1 order by id desc) as t)
order by id desc
速度也是很快的,是按主键排序的情况
其实思路是一样的,只是在“定位”的地方你用了min(id)。
Top
28 楼sfar(唏嘘2005)回复于 2005-08-02 09:18:14 得分 0
楼上的,据我所知,在查询里面多重嵌套子查询不是好的方法吧,速度很慢而且很容易出现不可预知的问题。Top
29 楼athossmth(athos)回复于 2005-08-02 09:27:34 得分 0
分页这种东西技巧不在sql中。Top
30 楼jasonwood007(帅哥@sina.com)回复于 2005-08-02 09:27:42 得分 0
我也想试下,不过怎样快速插入10万记录呢。。。Top
31 楼pupo(泡泡)回复于 2005-08-02 09:28:25 得分 0
如果记录号不连续呢??Top
32 楼lzdjoa(西边)回复于 2005-08-02 09:32:57 得分 0
markTop
33 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 09:33:40 得分 0
这个时 iuhxq 的方法。
在查询分析器力测试速度也是很快的,一下就出结果了。
用的是我的100万条记录的表,即使翻到10000,第一次1秒内返回,第二次一闪就出来了,估计是用了缓存Top
34 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 09:42:05 得分 0
to iuhxq
又试了一下你的方法,换成了最后回复时间的字段,效果比用主建,稍微差了一点。Top
35 楼wang790809(石头)回复于 2005-08-02 09:51:14 得分 0
对了,忘了最重要的一点 —— count(*)
翻页的时候没有用count(*)因为他会很占用内存的,也会很占用时间。
帖子的总数是记录在另一个表里的,用的时候去一下就行了
如果查询怎么办Top
36 楼powerllr(笨笨的招财鸡)回复于 2005-08-02 09:56:09 得分 0
学习~记录Top
37 楼iuhxq(小灰)回复于 2005-08-02 09:57:09 得分 0
我那个对主键排序可能还可以,对其他的有重复记录的无法分页,这个是最大的缺陷
因为出现重复记录后max和min函数都没用了。
对于特定场合,效率应该挺高(参考了:http://blog.csdn.net/lihonggen0/archive/2004/09/14/103511.aspx写的分页),因为第一次执行以后把总记录数就缓存了,以后不需要再查询记录数Top
38 楼brando_beat(Eの懒龙)回复于 2005-08-02 10:05:07 得分 0
upTop
39 楼bingbingcha(不思不归,不孟不E,原来是头大灰狼)回复于 2005-08-02 10:09:18 得分 0
这样的技巧在SQL区都讨论过了..速度是很快的..但是满足不了需求的..实用性太差了..现在的企业需要用到分页的大部分都是多表查询..单表分页满足不了需求的..
这个存储过程可以扩展..用临时表+楼主的方法..是个不错的选择..Top
40 楼iuhxq(小灰)回复于 2005-08-02 10:29:07 得分 0
临时表,我想知道通常的查询会返回多少总记录数
如果返回10万条记录,你要把10万个ID和自动增长列(20万个整数)放到临时表,这些数据是否能在内存中完成?如果不能,大约要占用多少硬盘缓存?Top
41 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 10:36:34 得分 0
to: wang790809
查询的时候就count(1)一下了,没有办法的事情了。
to : jasonwood007
用insert into 快速添加记录
insert into table1 ( col1,col2,col3......) select col1,col2,col3...... from table1
会把select出来的记录填到 table1 里面
执行一次,记录数就会加一倍,只需运行几次就行了。
Top
42 楼coldslayer(没事揣把刀)回复于 2005-08-02 10:38:59 得分 0
gzTop
43 楼iuhxq(小灰)回复于 2005-08-02 11:06:37 得分 0
select top 1 id from table2 order by id desc
select max(id) from table2
刚才测试,发现后面这个语句要比前面的语句慢的多!!!晕Top
44 楼zipo(程序员)回复于 2005-08-02 11:21:38 得分 0
gz
Top
45 楼amyzy(云淡风清)回复于 2005-08-02 11:44:29 得分 0
謝謝,学习!Top
46 楼programfanny()回复于 2005-08-02 13:21:29 得分 0
studying...Top
47 楼cxb_hy(一时的冲动)回复于 2005-08-02 15:00:39 得分 0
gz
Top
48 楼lstup(流水)回复于 2005-08-02 15:18:08 得分 0
我重asp转战到asp.net 最终还是发现 top是最好的分页方式,其次是not in。
不过具体代码看个人发挥了,差别不会太大 ^-^Top
49 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-02 18:27:59 得分 0
其次是 in 吧,怎么说in也会not in 好一点吧。
其实用top 的话,必须有索引的帮助的Top
50 楼heshi82215(enjoy java)回复于 2005-08-02 18:58:37 得分 0
学习中,慢慢看了..看来自己还是有很长的路要走....Top
51 楼jackyR(月夜随想 )回复于 2005-08-02 19:07:59 得分 0
支持,顶
================================================================
email:yueyesuixiang@163.com
================================================================
Top
52 楼dog0883(笨狗一条)回复于 2005-08-02 19:33:54 得分 0
学习Top
53 楼Allan1668(影子传说)回复于 2005-08-02 20:24:59 得分 0
学习Top
54 楼kmbirdman()回复于 2005-08-02 20:51:38 得分 0
不错,我这里还是很快的,楼主可以进行一下统计啊。
比如说在线人数,每个人访问所需时间等。Top
55 楼yangzixp(扬子(四川·巴中))回复于 2005-08-03 08:12:10 得分 0
有很大的局限性,我以前也研究过,如果没有主键,楼猪的分页存储过程能做吗?Top
56 楼yangzixp(扬子(四川·巴中))回复于 2005-08-03 08:13:00 得分 0
或者我的主键不是递增的那种,而是自己写的编号规则如:2005050500001Top
57 楼doitnow2000(大海)回复于 2005-08-03 08:22:17 得分 0
学习!Top
58 楼yynice(小楼听雨)回复于 2005-08-03 08:23:36 得分 0
多个字段排序怎么处理?Top
59 楼xcz1943(小钊)回复于 2005-08-03 08:24:58 得分 0
分页技术,markTop
60 楼tqg1023()回复于 2005-08-03 08:39:50 得分 0
学习一下Top
61 楼poseidonfan(失败,真失败。。。)回复于 2005-08-03 08:40:33 得分 0
以前我也这样用但是现在碰到一个问题主键+索引的列用uniqueidentifier类型标识的,
没有大小可以分,不能用<和>啊!
要是用
declare @SQLStr varchar(8000)
set @SQLStr='SELECT Top '+cast(@每页大小 as varchar)+' * FROM 表 WHERE 主键列 NOT IN (SELECT TOP '+cast(@每页大小*@第几页 as varchar)+' 主键列 from 表 )'
exec(@SQLStr)
就算是做成存储过程的话光光160000条记录取读取其中10条数据就要8秒左右。
大哥们帮忙想想办法啊!
是不是有办法把速度提高到2秒左右啊!Top
62 楼conghui(万物苏醒)回复于 2005-08-03 08:43:52 得分 0
学习Top
63 楼camelials(星期五)回复于 2005-08-03 08:51:38 得分 0
讨论过很多次的问题.
但是,又很难真正完美的解决.Top
64 楼zmn82025(鱼与水)回复于 2005-08-03 08:57:38 得分 0
学习ing...
谢谢楼主!Top
65 楼mzg008(长风宇)回复于 2005-08-03 09:15:08 得分 0
学习中..........Top
66 楼superfishmanweb(我也是千百个不愿意呀)回复于 2005-08-03 09:17:25 得分 0
markTop
67 楼dapanda()回复于 2005-08-03 09:18:40 得分 0
学习Top
68 楼wchwj(乡村艺人.华)回复于 2005-08-03 09:37:22 得分 0
学习,非常感谢!Top
69 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-03 09:39:47 得分 0
to:poseidonfan()
你的排序字段是什么呀?给它建立索引。然后就可以了呀
把我给的例子里的ID换成你的排序字段就可以了。
Top
70 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-03 09:45:39 得分 0
可能是受到我举的例子的影响吧,并不是只能按主键排序,论坛里就是按最后回复时间排序的,只要建立合理的索引就行了。
只需把ID字段改成你的排序字段可以了呀。
另外,一个表应该必须有一个主键吧,我觉得这是必须的,建议一不麻烦嘛。Top
71 楼poseidonfan(失败,真失败。。。)回复于 2005-08-03 09:59:07 得分 0
谢谢 jyk
我的表是记录系统日志用的,所以没有int类型数据,
不过到是有一个系统信息的时间类型!
这样感觉不行啊!Top
72 楼understand999()回复于 2005-08-03 10:03:42 得分 0
eform自定义表单平台是一个在IE浏览器中可视化的设计软件界面的工具。无论是输入界面还是报表界面,无论是简单的输入查询还是复杂的逻辑处理。都可以由eform设计出来。
eform自定义表单平台适用于网上OA系统的自定义表单模块,工作流系统的自定义表单模块,信息管理系统方面的软件开发项目等等。
Top
73 楼CExplorer(C++探索者)回复于 2005-08-03 10:27:15 得分 0
学习,Top
74 楼startray(孙悟空庄重宣布:从现在开始,国民进入抗日非常时期!(即不买卖日本的一切东西))回复于 2005-08-03 10:45:29 得分 0
留个记号Top
75 楼sarah19820826()回复于 2005-08-03 12:28:27 得分 0
收藏
Top
76 楼coolylh(【★★★★★正在奋斗中★★★★★】)回复于 2005-08-03 13:00:18 得分 0
markTop
77 楼maxxxz(ma)回复于 2005-08-03 13:12:14 得分 0
markTop
78 楼liuzxit(dotnetRGB.com)回复于 2005-08-03 13:12:32 得分 0
我看了之后就发现这种做法有很大局限性
果然,70多的回复只有一个星星,而且还是发表了否定的回复
老调重弹Top
79 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-03 13:19:30 得分 0
自欺欺人的成果。
你从来不删除记录么?你从来都是按照ID一种顺序排记录么?结合着两点来看,当增加记录的时候就只有顺序紧紧排在后边,否则你的成果就要破产。这样的ID是多么可怜。Top
80 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-03 13:20:37 得分 0
你说把ID改为自己的排序键,你到底好好想过怎么改么?Top
81 楼caichunmao(转瞬之间)回复于 2005-08-03 13:54:28 得分 0
我也用的方法和楼主差不多,但支持多表查询的分页,自己写了个类,可以把普通的查询SQL语句
进行解析,然后生成所需要取的分页区域中的记录,速度超级快,而且100万以上的记录取回数据只需要不到1秒的时间Top
82 楼zhiang75(zhiang75)回复于 2005-08-03 14:19:36 得分 0
to:楼主
....我认为这种翻页的方式或思路是我所看到效率最高的,最节约服务器资源的一种翻页方式...
当然不完美,其实这样的思路很简单
建一个唯一索引 ID ..按顺序递增 ,假设每页20条,取第20页的记录就是 where ID>400 and ID<=420
就可以了...
记录总会有删除的...ID不会永远连续 这就是这个思路最大的缺点...也是最不可投入使用的问题..
如何保证ID连续...这这个思路的最大要克服的问题
中国人有一句话,叫"没有条件创造条件也要上.."
因此如果单一的SQL不可以解决此问题,我们将进一步创造条件,来使用这个方式...
记录总会有删除的.....但是记录并不是总是立即删除的,就是说一个表中的执行删除语句的比例很小..一般将有1%就很多的了...大部分对表的操作集中在添加和更新上..
因此我在使用这样的翻页方式的时候..一般还要写一个服务..在数据删除..或失效的时候,将触发此服务,将已经不连续的ID字段,重新更新为连续的ID.....
这也是有问题要思考的...删除操作的执行概率..一般是对新记录的执行比较多...因此重新编写连续索引的方式可以从删除的数据的索引开始,这也是优化的一种方式
其实重新编写索引的SQL很简单
UPDATE 你的表
SET ID=ID-1
where ID>删除的ID
此SQL我们可以嵌入这个表的触发器中
..当然这是一种解决方案
也可以使用一种更让人不可思议的方式来解决...就是写一个后台服务...根据希望的条件(比如每天晚上4点)来触发执行...重新编写表的连续索引...这样是占用系统资源最好的解决方式..但是会造成错误.不应该是错误..应该是不精确...当然我无法想象当你给用户返回一页数据的时候用户会去数这一页是否是20条?哈哈要是真有这样用户你就不要告诉他你要没页都给他返回20条了...把实际数量告诉它就完了....
欢迎拍砖
Top
83 楼zhiang75(zhiang75)回复于 2005-08-03 14:44:33 得分 0
...问题并没有解决...当 where 了其他条件后...怎么办?
ID肯定不会连续...我以前使用临时表..再建一个连续的索引...
现在不会了...我在客户端分页...我把所有的客户查寻到的数据返回给客户...可以用脚本..
太多用JAVA APP
既然客户需要这样多的数据..那就都给你....你的计算机自己慢慢玩去吧...
从而迫使用户慎重选择他的查询条件....要不查询条件不就成摆设了..哈哈.
Top
84 楼sd166(原来如此)回复于 2005-08-03 14:57:54 得分 0
关注Top
85 楼ildp()回复于 2005-08-03 15:21:31 得分 0
学习Top
86 楼xjzgl(sdfs)回复于 2005-08-03 15:43:24 得分 0
upTop
87 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-03 16:06:22 得分 0
“没有条件创造条件也要上”,也要实事求是。有一种有名的悖论:如果把一只猴子放在图书馆里的一台电脑前足够长时间,它可以打出图书馆里全部著作。
如果这就叫做智能,就没有必要继续去抓住不放了。
所以,你要知道,每一次查询之前都把百万条记录重新顺序编号,这既是对单用户就够呛了,何况数据库是并发用户互相加锁的,所花的时间比翻页一万次还要多。Top
88 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-03 16:10:07 得分 0
如果你测试,就应该编写出顺序编号的程序,然后把它与翻页程序顺序放在一起,所花的时间是这两个操作之和!因为在多用户状态下,你不能保证翻页前id号顺序是没有任何瑕疵的,必须重新编号,并且在编号之后、翻页之前还要所住数据表,否则你翻页的时候别人删除了一条记录或者增加了一条记录,你就应该立刻重新计算编号。
不把两快时间加在一起,这个“高速”的结论站不住脚。Top
89 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-03 16:16:31 得分 0
每一个删除、修改、添加(后两项造成记录应该排列的顺序改变)的时候都要把百万记录顺序更新一遍?这直接是折腾死(锁)数据库。
何况用户是先在界面上查询、排序,然后你实时给他显示仅符合他要求的结果,可以肯定这个所谓的高速方法真正实用中一般是最低效率的一种。Top
90 楼yangzhixue(浪子软件)回复于 2005-08-03 16:45:39 得分 0
学习ing.Top
91 楼xifan930()回复于 2005-08-03 17:08:01 得分 0
标记Top
92 楼Aden(Aden)回复于 2005-08-03 17:47:45 得分 0
markTop
93 楼zhiang75(zhiang75)回复于 2005-08-03 18:27:41 得分 0
评价:
有一种有名的悖论:如果把一只猴子放在图书馆里的一台电脑前足够长时间,它可以打出图书馆里全部著作。
假设一只猴子打出图书馆里全部著作的时间是n n的条件当然应该是 n>0 and n<无穷大.....
假设 n=1亿年 ..很长吧...没有一只猴子可以活这样长的....这件事根本就不可能完成..呵呵
要是找1亿只猴子来做呢? 一年就可以了吧....
当然找1亿只猴子也是很困难的..呵呵,但这件事至少是有可能可以完成的对吗?..哈哈
这就是"没有条件创造条件也要上"的精髓....
Top
94 楼dolfen(网海之豚(每天进步一点点))回复于 2005-08-03 18:32:51 得分 0
收藏Top
95 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-03 19:56:17 得分 0
to:sp1234
100万条记录,我是用 insert into table1 (...) select ... from table1
的方式添加的,加之前就已经建立索引了,
16条数据很快就变成了100万。
再说修改,我用企业管理器打开表,修改了一个字段,恩,的确很慢,但这是什么原因呢?
查看了一下SQL占用的内存,从30多M,变成了100多M,难怪要很慢,
但是再次修改的时候就很快了,修改排序字段的时候也是一样的,
根本就没有感觉,不查看内存容量的话,和操作几百条记录的表是一样的。
当然,删除也是一样的效果。
难道你们没有看我的论坛吗?我的论坛是按最后回复时间排序的呀!!
用100到1来举例,只是为了便于说明呀。
是我没写清楚还是。。。。。。
难道看不懂我写的查询语句吗?
to::zhiang75(zhiang75)
送给你100万个板砖吧!
Top
96 楼pclogic(跃虹鸟)回复于 2005-08-03 20:13:55 得分 0
收藏Top
97 楼iloveyour(爱老虎油)回复于 2005-08-03 20:25:37 得分 0
做个记号Top
98 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-03 21:49:49 得分 0
在to:sp1234
不知道你在说些什么!!!
我又不是在这里空讲理论,我可是拿出了实例的呀,难道你没有看一看吗?
难道我用的是假数据吗?
我写了那么多,算法只占了一小部分,其他的地方说了很多,都是骗人的吗?
说我的方法不行的人,请拿出你们的方法!!!
对了我在论坛里加了,修改、删除的功能,你看一看执行时间!!!
Top
99 楼hanhuole(火星来的程序员)回复于 2005-08-03 22:07:33 得分 0
mark一个Top
100 楼sun8087(.Net@ChangZhou)回复于 2005-08-03 22:27:56 得分 0
参考Top
101 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-03 22:29:42 得分 0
感谢 sp1234 这么捧场,发了这么多的帖子来帮我顶。
=========
如果把一只猴子放在图书馆里的一台电脑前足够长时间,它可以打出图书馆里全部著作。
=========
猴子会打字吗?(在键盘上乱按的不算!)
猴子认识字吗?
让猴子打字亏你想得出来!
你要是想把图书馆里的书都录到电脑里,那你可以自己来嘛。
嫌累的话找几个人帮忙!
还累的话,买一个扫描仪来帮忙。
怎么不想点可行的和提高效率的方法呢???
Top
102 楼lywf(痛快去爱)回复于 2005-08-03 23:13:27 得分 0
markTop
103 楼keyu21(科宇)回复于 2005-08-03 23:15:42 得分 0
markTop
104 楼JzeroBiao(先知)回复于 2005-08-03 23:17:10 得分 0
学习.Top
105 楼Edisoncat(http://www.Edisonliu.com)回复于 2005-08-03 23:30:17 得分 0
学习,非常牛Top
106 楼wwwafa9(阿发)回复于 2005-08-03 23:48:02 得分 0
收藏Top
107 楼ShengNet(打败.net)回复于 2005-08-03 23:59:53 得分 0
好强的人气,先看看Top
108 楼sunruping(孙茹苹)回复于 2005-08-04 08:19:21 得分 0
看看Top
109 楼pupo(泡泡)回复于 2005-08-04 08:35:55 得分 0
100w条,如果删除第一条,为了让它连续那你岂不是要更新999999条记录,那你就只有等死吧...Top
110 楼axiang80(四月风)回复于 2005-08-04 08:51:58 得分 0
学习Top
111 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 09:02:40 得分 0
每一次需要显示的时候都需要重新计算每一条记录的ID,如果你不能理解所谓的增加、删除、修改的时候只是测试修改其它某条记录的某个字段,这种测试根本牛头不对马嘴了。
其实我故意忽略很多要求,而认为搂主能够想象这些基本要求。但是看来需要我帮搂住增加一点想象力。我举个例子:在户籍管理网络上,现在“只有”两个用户,第一个用户要查看所有年龄大于16岁的人的资料,第二个人额外要查询所有男人的,就算“每次都重新计算ID”对你的数据库来说是飞快的,又怎样将数据库的ID同时修改为适合这两个人的要求的顺序ID号呢?Top
112 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 09:05:19 得分 0
博物馆里的猴子,影射出很多人的所谓高明算法是自己给自己设计了一个根本达不到的条件,还觉得自己发现的算法规则何人的都方便。Top
113 楼chuxuecharp(初学者)回复于 2005-08-04 09:12:40 得分 0
不错,学习Top
114 楼zhiang75(zhiang75)回复于 2005-08-04 09:19:44 得分 0
做事情要讲究因地制宜,都说冒泡排序比快排慢....但是在小规模数据量的情况下,比如6条,快排不见得比冒泡快...同样的,就算在这样的情况下快排比冒泡快..有能快百分之几呢?,在这样的情况下我肯定用冒泡,不用快排....
任何算法,或思路都是有它的适用范围的..楼主的思路也是一样的...
100w条,如果删除第一条,为了让它连续那你岂不是要更新999999条记录,那你就只有等死吧...
这个问题你的条件不全..你应该告诉我这样的情况发生的概率是多少?10年一次?1秒中10次?
不过对于LZ的BBS应用来说..假设是一个中等的BBS,每个论坛每天进贴500
那么有100W条记录的发生时间应该与第一条记录相隔 100w/500/365=5.48年
我真是无法想象有哪个斑竹和你一样,想删除5.48年前的一个记录...
当然了就算斑竹和你一样,删了5.48年前的一个让他痛恨了5.48年的帖子(有点小人得志的感觉)...系统死了......
因为这样的事情每隔5.48年才会发生..我想...大家都会谅解的..呵呵Top
115 楼zhiang75(zhiang75)回复于 2005-08-04 09:43:30 得分 0
to:sp1234(就要离开兰州了)
其它的我都不用考虑....这个算法最大缺陷就是,不可以Where 其它条件,就是说不可以条件查询..就是说条件查询必然导致此算法的优势(效率)丧失
我看到LZ的网站中也没有找到搜索的功能...
不过我想既然搜索的功能不适用此算法,就干脆不用了..可以使用其它的方法的..
每个算法都是有自己的适用范围的..
我从来没有考虑过完美的算法,我只考虑完美的软件应用.....我的工作就是把不完美的算法放到程序中合适的位置...然后组装出完美的软件应用
Top
116 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 10:38:23 得分 0
不是的。如果有了where、order,那么ID作为从1开始的顺序号就自相矛盾了。如果ID不是这个作用,程序中定位所显示页面的记录的算法就根本不成立!!!Top
117 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 10:40:48 得分 0
另外作为一个“典型”去宣传,不能不去自我揭示限制,而反而把它当作一个“通用”的例子。
其实如果搂主只要稍微提示一下这个例子的限制,我也就不去说明他的限制了。Top
118 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 10:48:48 得分 0
比如说,对于 CSDN 这样的论坛,假设说他承诺的帖子永远不过期(对了,他的新式插在帖子第1号之前的,搂主的算法立刻被枪毙了),程序员也不能就在csdn一旦维护服务器数据(例如数据库修复之后、或者其它新创意实施之后)将责任推卸。否则,这样的程序员创造的所谓算法其实是定时炸弹。Top
119 楼lily_no(丽丽的新衣服)回复于 2005-08-04 10:51:07 得分 0
upTop
120 楼share1011(不知道)回复于 2005-08-04 11:11:19 得分 0
cccccTop
121 楼loverdotnet(西瓜)回复于 2005-08-04 11:26:05 得分 0
markTop
122 楼zhiang75(zhiang75)回复于 2005-08-04 11:40:47 得分 0
..............我相信,大家在看了这样的讨论后会明白此算法的局限的.....Top
123 楼pupo(泡泡)回复于 2005-08-04 12:56:49 得分 0
我就不考虑100W条,考虑10W8W的都够呛,一天删除的帖子也不是一两条.再一个,作为索引ID,一般都会关联其他表,就是用触发器或主外键关联更新,你自己去算算更新的记录数吧..Top
124 楼pupo(泡泡)回复于 2005-08-04 13:00:12 得分 0
你用这条语句实验下,几个人同时删除几条信息不锁死你才怪
UPDATE 你的表
SET ID=ID-1
where ID>删除的IDTop
125 楼jimmyzhu25(勿以分少而不为,勿以分多而为之)回复于 2005-08-04 13:10:14 得分 0
markTop
126 楼sugengnn(sugengnn)回复于 2005-08-04 16:56:44 得分 0
UPTop
127 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 17:19:54 得分 0
又顶上来了,我就顺便结合“泡泡”的SQL代码评论一下:
UPDATE 你的表
SET ID=ID-1
where ID>删除的ID
这语句其实比真正的编号程序执行得“快很多”,是因为这个程序并没有执行顺序编号程序,SQL Server实际上是预先在临时表中计算出所有Id-1,然后一次性地更新所有记录。只有一个update命令,SQL Server只执行一次命令分析规划操作。(察看规划分析输出)
而顺序编号,需要写一个while循环,然后每条语句都执行一个update命令,也就是说100W记录就要执行100W个Update命令。
如果写成一个SQL,可以这样:
declare @n int
set @n=1
update 你的表 set id=@n,@n=@n+1 order by id
这其实是update命令的副作用,SQL Server未公开承认update是顺序执行的,因此此方法并不保证永远有效。
Top
128 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2005-08-04 17:22:25 得分 0
不知道我说明白了没有。
update myTable set id=id-1
并没有逐一记录中间的id值,SQL Server对于赋值右边的字段值,update过程中永远不改变。所以必须使用@n临时变量代替。
可以将几乎所有的while循环语句改写为简练的形式。Top
129 楼word1120(字母)回复于 2005-08-04 17:37:30 得分 0
markTop
130 楼zhiang75(zhiang75)回复于 2005-08-05 09:51:06 得分 0
晕了晕了..
到底是用
UPDATE 你的表
SET ID=ID-1
where ID>删除的ID
还是要用
declare @n int
set @n=1
update 你的表 set id=@n,@n=@n+1 order by id
Top
131 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-07 07:57:47 得分 0
UPDATE 你的表
SET ID=ID-1
where ID>删除的ID
这么写可以达到 ID字段的值减一的目的。
declare @n int
set @n=1
update 你的表 set id=@n,@n=@n+1 order by id
这种方法没有试过。
另外ID只是不能改变的,就像你的身份证号一样是不能随意换的。
这里只是说SET columns = columns - 1 可以让字段的值减一。
举例:
原来的字段值:
1,2,3,6,10,30
执行后的值
0,1,2,3,5,9,29
再有就是我的分页算法,根本就不用维护连续的字段值,不要受sp1234的迷惑。
http://community.csdn.net/Expert/TopicView3.asp?id=4189627
这里有详细的解释。
Top
132 楼pupo(泡泡)回复于 2005-08-08 11:25:59 得分 0
不维护连续的字段值
我不知道你怎么能准确的计算出标记ID号
set @Count = @pageSize * (@CurPage -1) + 1
假设我的ID
1,2,3,100,200,300
每页10条,你这个要给我分成多少页呢Top
133 楼mybordy(mybordy)回复于 2005-08-08 11:33:35 得分 0
markTop
134 楼wyheaven(革命尚未成功!)回复于 2005-08-08 11:43:32 得分 0
upTop
135 楼pupo(泡泡)回复于 2005-08-08 12:50:11 得分 0
看了你的另外网址的说明,原来是我理解错了,我以为标记ID是直接通过计算得出来,原来也是通过类似top的方法计算出来的,楼主这种方法还是挺不错的!Top
136 楼pupo(泡泡)回复于 2005-08-08 13:24:13 得分 0
不过楼主这个方法csdn里面老早有介绍的文章了
http://dev.csdn.net/article/43/43936.shtmTop
137 楼ioul(倒飞,不见地平线)回复于 2005-08-08 14:22:28 得分 0
mark
Top
138 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-08-11 07:49:17 得分 0
to:pupo(泡泡)
http://dev.csdn.net/article/43/43936.shtm
看了一下,讲得很详细,做了很多的测试,总体来说挺好。
但是,他并没有提到我的方法,虽然思路相同,但是写法且不一样。
另外,那篇文章里有一个明显的错误:
in 是可以利用所引的,or也是可以的
select * from table where ID in (2,3)
select * from table where ID =2 or ID = 3
像这样的语句,如果ID是主键(或者设置的索引),那么是可以利用索引的。
还有呢就是有一个明显的局限性 —— 单字段排序!
好像没有说明多字段排序要怎么处理。
Top
139 楼adandelion(水源是CSDN最黑的地方,但这个最黑是CSDN一手制造的!)回复于 2005-08-11 08:03:06 得分 0
GZTop
140 楼pmmx(胖子)回复于 2005-09-09 10:16:14 得分 0
markTop
141 楼pclogic(跃虹鸟)回复于 2005-09-09 18:41:03 得分 0
markTop
142 楼kenhit2()回复于 2005-09-12 09:32:11 得分 0
markTop
143 楼rootX(rootX)回复于 2005-09-17 00:19:59 得分 0
to楼住:
这个方法其实动网(DVBBS)的SQL存储过程版本已经用了好多年了。。。不过效率的确是很高的Top
144 楼lostinwind(包子店老板)回复于 2005-09-17 09:25:54 得分 0
快速插入记录的一个要点就是表的索引越少越好
曾经看过一个文章,说FOXPRO插入记录的速度是最快的,为什么呢?
因为foxpro太简单了,没有什么管理单元,单纯的一个(文本)文件,而MSSQL等数据库就不同了,需要做一些外围的工作,比如用户认证,日志回写等。
记得上oracle认证的时候老师也告诉过我们,索引和更新数据的速度是对矛盾,因为数据库的记录发生变化了,必须维护相应的索引。Top
145 楼lostinwind(包子店老板)回复于 2005-09-17 09:41:53 得分 0
另外,对于数据库的查询性能的提高,我可以提供一篇好帖子,比较详细
http://www.itpub.net/2773.html
Top
146 楼YuLimin(阿敏总司令:简单就是美—钻石闪闪您快结贴!)回复于 2005-11-01 10:02:35 得分 0
不错吧,应当,此贴上了程序员2005.09HOT10之一哦:)Top
147 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2005-11-07 13:43:55 得分 0
是真的吗?
我要买一本看一看。:)Top
148 楼bj20082005(asd)回复于 2006-01-17 10:36:34 得分 0
markTop
149 楼flashasp(flashasp)回复于 2006-01-19 23:52:31 得分 0
强贴啊!Top
150 楼jxjjljf(不用存储我不甘心啊)回复于 2006-01-24 14:37:38 得分 0
mTop
151 楼jeedispeed()回复于 2006-01-27 20:27:06 得分 0
markTop
152 楼tigerhu76(虎虎)回复于 2006-01-31 20:35:06 得分 0
学习Top
153 楼aafly(和安飞翔)回复于 2006-03-03 10:39:14 得分 0
markTop
154 楼imsyq(达到)回复于 2006-04-23 19:58:31 得分 0
MARKTop




