大数据量表如何统计行数?(1000万行数据以上)

今天讨论一个问题:当一个表有1000万行以上的数据,我们如何知道这个表中的数据行数?起初我们说用count来统计,但是这样做的是错误的.当有多个count的sql语句查询的时候会出现服务器受不了的情况.那怎么做呢?
一个哥们提出了一个方法:
建立一张新表两个字段TableName(表明)RowCount(行数),当数据插入和删除的时候我们就在这个表中对相应的数据行进行+1和-1的修改.这样我们统计行数的时候就不用去count表了.
有个问题如果我要统计的行数是要在某张表的一个列的进行where语句怎么办?多个列呢?
谁有解决的办法可以提出来.暂时还没有解决

posted @ 2007-08-08 18:23 H2O、winnerzone 阅读(2534) 评论(18)  编辑 收藏

  回复  引用  查看    
#1楼 2007-08-08 18:29 | xingd      
老老实实select count,where条件中字段建立索引,超大的数据表进行分区。
  回复  引用    
#2楼 2007-08-08 18:37 | HAL [未注册用户]
条件字段有索引的话, 尽管放心去count.
  回复  引用  查看    
#3楼 2007-08-08 19:28 | 丁学      
有索引就不怕,count嘛,索引挡了
  回复  引用  查看    
#4楼 2007-08-08 19:37 | RicCC      
可以尝试从索引统计信息里面找
SELECT CAST(idx.rowcnt AS bigint) AS [RowCount]
FROM dbo.sysobjects AS tbl
INNER JOIN dbo.sysindexes AS idx ON idx.id = tbl.id and idx.indid < 2
WHERE (tbl.type='U' or tbl.type='S') and tbl.name=N'表名'

依赖于统计信息的准确程度,找到的记录数不一定100%准确
  回复  引用  查看    
#5楼 2007-08-08 20:02 | 金色海洋(jyk)      
count 的效率和有没有所以是没有关系的。
count 是做什么的?说白了就是数数的。有两条记录就要从一数到二;有一万条记录,就要从一数到一万,一点懒都偷不了的。索引也帮不上忙。

你加where 查询条件也好,不加查询条件也好,加索引也好,不加索引也好,
count 永远都要数一遍符合条件的记录。这一步是在最后执行的。

那么为什么会有加了索引 count就快了的感觉呢?其实不是快在count上,而是快在查询数据上,因为查询数据的速度快了,所以才会误认为count的速度也快了,

什么?您不信。没关系,可以试一下。

假设一个表里有一千万条记录,有一个kind 字段,字段的值是1,2,3,4,5......这样的数字。

假设 kind字段有索引

在假设 kind = 1 的记录有十条,kind = 2 的记录有一万条,kind = 3 的记录有一百万条。


好了假设完毕,开始测试了。

select count(1) from table1 where kind = 1
select count(1) from table1 where kind = 2
select count(1) from table1 where kind = 3

看一看这三个语句的反应速度。


好像说了一些没用的,我的不太好的解决方法。

1、如果读取表里的全部记录,或者按照分类读取的话,那么可以像博主说的用另一个表来记录数据的记录数。

建立一个表 ,三个字段——注意是三个或者更多——TableName(表明),分类RowCount(行数),
字段不够的话就在加。


2、如果有where 也就是查询的话,那就得老老实实地去数数了。只能寄希望于符合条件的记录数少一点(一万以内吧)。

如果不想这么被动的话呢,可以给记录加一个“优先级”,先查询优先级高的,如果在高的里面已经有一千条记录了,那么就不用再在优先级低的记录里找了。
比如搜索引擎,一次查询最多只返回一千条记录。

如果要求查询结果非常精确的话,那也没有太好的办法了。在加几个服务器吧。


  回复  引用  查看    
#6楼 2007-08-08 20:57 | 金色海洋(jyk)      
对了还有一招就是“假记录数”,如果说你已经把一个表里的记录数保存到另一个表里了,那么在查询的时候,符合条件的记录数一定不会大于这个数,可以在这个数的基础上减少一点,作为查询得到的记录数。
  回复  引用    
#7楼 2007-08-08 22:22 | seamusic [未注册用户]
仿佛百度的搜索就是用那个假的数据,特别是收纳比较多的个人博客,再翻多几页就会出现真实的数值了……
  回复  引用  查看    
#8楼 2007-08-09 00:34 | superhasty      
没有人知道sp_spaceused?
  回复  引用  查看    
#9楼 2007-08-09 01:24 | overred      
1000w select count(1) 是没问题的 看你服务器的配置拉
  回复  引用  查看    
#10楼 2007-08-09 06:39 | 金色海洋(jyk)      
1000w select count(1) 运行一两次是没有什么问题的,但是架不住没完没了地运行呀。
  回复  引用    
#11楼 2007-08-09 08:33 | yaolp [未注册用户]
1.硬件,提升IO,CPU等;
2.表分区;
3.索引;
4.优化SQL;
  回复  引用  查看    
#12楼 [楼主]2007-08-09 09:49 | winnerzone      
@金色海洋(jyk)
谢谢你的详细分析.要我也学到了很多.
  回复  引用    
#13楼 2007-08-09 11:04 | 哲男 [未注册用户]
厉害厉害,佩服佩服
  回复  引用  查看    
#14楼 2007-08-09 14:02 | aspnetx      
建立数据仓库
对一些数据进行聚合,形成多维数据集

恩,自己感觉好像也是在拿大炮轰蚊子,呵呵,来凑个数还是可以的吧
  回复  引用    
#15楼 2007-08-09 17:41 | pjdu [未注册用户]
exec sp_spaceused 'tblname'
  回复  引用  查看    
#16楼 2007-08-09 23:31 | Zealot      
同意一楼的观点,但要注意where条件的字段不要用聚集索引,用了会很慢。
刚刚在30w行的一个表上做了实验,证实了这一点。
网上有个关于5阶B树的排序过程演示flash,可以很好的说明这一点。

  回复  引用  查看    
#17楼 2007-08-09 23:55 | Jackei      
RicCC 的是正解,不过还可以优化一下。

建议上面用 count 的都回去好好了解一下 SQL Server 的系统表和视图。
  回复  引用  查看    
#18楼 2007-08-10 12:39 | 金色海洋(jyk)      
create procedure sp_spaceused --- 1996/08/20 17:01
@objname nvarchar(776) = null, -- The object we want size on.
@updateusage varchar(5) = false -- Param. for specifying that
-- usage info. should be updated.
as

declare @id int -- The object id of @objname.
declare @type character(2) -- The object type.
declare @pages int -- Working variable for size calc.
declare @dbname sysname
declare @dbsize dec(15,0)
declare @logsize dec(15)
declare @bytesperpage dec(15,0)
declare @pagesperMB dec(15,0)

/*Create temp tables before any DML to ensure dynamic
** We need to create a temp table to do the calculation.
** reserved: sum(reserved) where indid in (0, 1, 255)
** data: sum(dpages) where indid < 2 + sum(used) where indid = 255 (text)
** indexp: sum(used) where indid in (0, 1, 255) - data
** unused: sum(reserved) - sum(used) where indid in (0, 1, 255)
*/
create table #spt_space
(
rows int null,
reserved dec(15) null,
data dec(15) null,
indexp dec(15) null,
unused dec(15) null
)

/*
** Check to see if user wants usages updated.
*/

if @updateusage is not null
begin
select @updateusage=lower(@updateusage)

if @updateusage not in ('true','false')
begin
raiserror(15143,-1,-1,@updateusage)
return(1)
end
end
/*
** Check to see that the objname is local.
*/
if @objname IS NOT NULL
begin

select @dbname = parsename(@objname, 3)

if @dbname is not null and @dbname <> db_name()
begin
raiserror(15250,-1,-1)
return (1)
end

if @dbname is null
select @dbname = db_name()

/*
** Try to find the object.
*/
select @id = null
select @id = id, @type = xtype
from sysobjects
where id = object_id(@objname)

/*
** Does the object exist?
*/
if @id is null
begin
raiserror(15009,-1,-1,@objname,@dbname)
return (1)
end


if not exists (select * from sysindexes
where @id = id and indid < 2)

if @type in ('P ','D ','R ','TR','C ','RF') --data stored in sysprocedures
begin
raiserror(15234,-1,-1)
return (1)
end
else if @type = 'V ' -- View => no physical data storage.
begin
raiserror(15235,-1,-1)
return (1)
end
else if @type in ('PK','UQ') -- no physical data storage. --?!?! too many similar messages
begin
raiserror(15064,-1,-1)
return (1)
end
else if @type = 'F ' -- FK => no physical data storage.
begin
raiserror(15275,-1,-1)
return (1)
end
end

/*
** Update usages if user specified to do so.
*/

if @updateusage = 'true'
begin
if @objname is null
dbcc updateusage(0) with no_infomsgs
else
dbcc updateusage(0,@objname) with no_infomsgs
print ' '
end


set nocount on

/*
** If @id is null, then we want summary data.
*/
/* Space used calculated in the following way
** @dbsize = Pages used
** @bytesperpage = d.low (where d = master.dbo.spt_values) is
** the # of bytes per page when d.type = 'E' and
** d.number = 1.
** Size = @dbsize * d.low / (1048576 (OR 1 MB))
*/
if @id is null
begin
select @dbsize = sum(convert(dec(15),size))
from dbo.sysfiles
where (status & 64 = 0)

select @logsize = sum(convert(dec(15),size))
from dbo.sysfiles
where (status & 64 <> 0)

select @bytesperpage = low
from master.dbo.spt_values
where number = 1
and type = 'E'
select @pagesperMB = 1048576 / @bytesperpage

select database_name = db_name(),
database_size =
ltrim(str((@dbsize + @logsize) / @pagesperMB,15,2) + ' MB'),
'unallocated space' =
ltrim(str((@dbsize -
(select sum(convert(dec(15),reserved))
from sysindexes
where indid in (0, 1, 255)
)) / @pagesperMB,15,2)+ ' MB')

print ' '
/*
** Now calculate the summary data.
** reserved: sum(reserved) where indid in (0, 1, 255)
*/
insert into #spt_space (reserved)
select sum(convert(dec(15),reserved))
from sysindexes
where indid in (0, 1, 255)

/*
** data: sum(dpages) where indid < 2
** + sum(used) where indid = 255 (text)
*/
select @pages = sum(convert(dec(15),dpages))
from sysindexes
where indid < 2
select @pages = @pages + isnull(sum(convert(dec(15),used)), 0)
from sysindexes
where indid = 255
update #spt_space
set data = @pages


/* index: sum(used) where indid in (0, 1, 255) - data */
update #spt_space
set indexp = (select sum(convert(dec(15),used))
from sysindexes
where indid in (0, 1, 255))
- data

/* unused: sum(reserved) - sum(used) where indid in (0, 1, 255) */
update #spt_space
set unused = reserved
- (select sum(convert(dec(15),used))
from sysindexes
where indid in (0, 1, 255))

select reserved = ltrim(str(reserved * d.low / 1024.,15,0) +
' ' + 'KB'),
data = ltrim(str(data * d.low / 1024.,15,0) +
' ' + 'KB'),
index_size = ltrim(str(indexp * d.low / 1024.,15,0) +
' ' + 'KB'),
unused = ltrim(str(unused * d.low / 1024.,15,0) +
' ' + 'KB')
from #spt_space, master.dbo.spt_values d
where d.number = 1
and d.type = 'E'
end

/*
** We want a particular object.
*/
else
begin
/*
** Now calculate the summary data.
** reserved: sum(reserved) where indid in (0, 1, 255)
*/
insert into #spt_space (reserved)
select sum(reserved)
from sysindexes
where indid in (0, 1, 255)
and id = @id

/*
** data: sum(dpages) where indid < 2
** + sum(used) where indid = 255 (text)
*/
select @pages = sum(dpages)
from sysindexes
where indid < 2
and id = @id
select @pages = @pages + isnull(sum(used), 0)
from sysindexes
where indid = 255
and id = @id
update #spt_space
set data = @pages


/* index: sum(used) where indid in (0, 1, 255) - data */
update #spt_space
set indexp = (select sum(used)
from sysindexes
where indid in (0, 1, 255)
and id = @id)
- data

/* unused: sum(reserved) - sum(used) where indid in (0, 1, 255) */
update #spt_space
set unused = reserved
- (select sum(used)
from sysindexes
where indid in (0, 1, 255)
and id = @id)
update #spt_space
set rows = i.rows
from sysindexes i
where i.indid < 2
and i.id = @id

select name = object_name(@id),
rows = convert(char(11), rows),
reserved = ltrim(str(reserved * d.low / 1024.,15,0) +
' ' + 'KB'),
data = ltrim(str(data * d.low / 1024.,15,0) +
' ' + 'KB'),
index_size = ltrim(str(indexp * d.low / 1024.,15,0) +
' ' + 'KB'),
unused = ltrim(str(unused * d.low / 1024.,15,0) +
' ' + 'KB')
from #spt_space, master.dbo.spt_values d
where d.number = 1
and d.type = 'E'
end

return (0) -- sp_spaceused

GO


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
 
另存  打印