分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)

分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)

不少时候咱们都须要计算数据库中各个表的数据量和每行记录所占用空间程序员

这里共享一个脚本sql

CREATE TABLE #tablespaceinfo
    (
      nameinfo VARCHAR(500) ,
      rowsinfo BIGINT ,
      reserved VARCHAR(20) ,
      datainfo VARCHAR(20) ,
      index_size VARCHAR(20) ,
      unused VARCHAR(20)
    )  
 
DECLARE @tablename VARCHAR(255);  
 
DECLARE Info_cursor CURSOR
FOR
    SELECT  '[' + [name] + ']'
    FROM    sys.tables
    WHERE   type = 'U';  
 
OPEN Info_cursor  
FETCH NEXT FROM Info_cursor INTO @tablename  
 
WHILE @@FETCH_STATUS = 0
    BEGIN 
        INSERT  INTO #tablespaceinfo
                EXEC sp_spaceused @tablename  
        FETCH NEXT FROM Info_cursor  
    INTO @tablename  
    END 
 
CLOSE Info_cursor  
DEALLOCATE Info_cursor  
 
--建立临时表
CREATE TABLE [#tmptb]
    (
      TableName VARCHAR(50) ,
      DataInfo BIGINT ,
      RowsInfo BIGINT ,
      Spaceperrow AS ( CASE RowsInfo
                         WHEN 0 THEN 0
                         ELSE DataInfo / RowsInfo
                       END ) PERSISTED
    )

--插入数据到临时表
INSERT  INTO [#tmptb]
        ( [TableName] ,
          [DataInfo] ,
          [RowsInfo]
        )
        SELECT  [nameinfo] ,
                CAST(REPLACE([datainfo], 'KB', '') AS BIGINT) AS 'datainfo' ,
                [rowsinfo]
        FROM    #tablespaceinfo
        ORDER BY CAST(REPLACE(reserved, 'KB', '') AS INT) DESC  


--汇总记录
SELECT  [tbspinfo].* ,
        [tmptb].[Spaceperrow] AS '每行记录大概占用空间(KB)'
FROM    [#tablespaceinfo] AS tbspinfo ,
        [#tmptb] AS tmptb
WHERE   [tbspinfo].[nameinfo] = [tmptb].[TableName]
ORDER BY CAST(REPLACE([tbspinfo].[reserved], 'KB', '') AS INT) DESC  

DROP TABLE [#tablespaceinfo]
DROP TABLE [#tmptb]

注意:使用以前要计算哪一个数据库的记录,请先USE一下要统计表记录数的那个数据库!!数据库

 


工做中遇到的问题服务器

能够说我在实际的工做中 ,在100个问题中有90个都会先用到这个脚本架构

这里举一个我本人工做中遇到的一些问题框架

 

问题一:spa

程序员反映数据库查询慢,5分钟尚未出结果设计

我先用这个脚本看一下这个表有多少记录,大概有1000w+条数据3d

而后在本地的SSMS里查询,确实也是大概4分钟的样子才出来数据,看一下执行计划,发现查询能使用到索引code

看一下数据库的压力,并非很大,我跟会不会跟数据量有关系呢?

程序员要查询的结果条数是500条数据,业务表是作了分区的,按道理应该不会慢成这样。。。

后来我再看一下共享出来的那个脚本的结果,发现查询的结果大小=每行记录的大小*记录数

要查询大概500MB的数据,再传到客户端,不慢才怪

 

为什麽查询出的结果这么大?

主要是有几个大字段:例如:二进制字段和NVARCHAR(MAX)

而且时间范围跨度比较大

 

立刻叫程序员改一下查询的语句,因为是entity framework程序,怎麽改我就不太清楚了,主要是没必要要的字段就不查询处理而且缩小时间范围

 

问题二:

还有一些问题也须要知道每行记录的大小,例如删除表的历史数据,QA说要保留2013年以前的数据,你须要查出保留的数据或者2013年以前的数据占用多少G空间

再结合当前服务器的磁盘可用空间,来评估删除的数据是否太多或者太少

那么流程是:先查出2013年以前的记录数有多少-》计算表的总记录数-》计算表的大小-》手工计算每行记录的大小-》乘以2013年以前的记录数

若是没有每行记录数这个字段,那么你手工计算,是否是效率就变慢了???

 

问题三:

导数据的时候,你想知道当前已经导了多少数据了,那么执行一下这个脚本就能够了,这个脚本基本不会被阻塞

很快就能查出结果


脚本的计算方法

方法一

实际上利用的就是数据行大小的信息除以记录数

CASE RowsInfo
WHEN 0 THEN 0
ELSE DataInfo / RowsInfo

 

 

 方法二

SELECT AVG(DATALENGTH(C0))+AVG(DATALENGTH(C1))+AVG(DATALENGTH(C2))+AVG(DATALENGTH(C3)) FROM [dbo].[TB106]

 

说一下两种方法的区别

第一种方法是效率高,当表有上亿条记录的时候,若是你使用第二种方法执行AVG(DATALENGTH(C0))是很慢的,由于SQLSERVER要统计字段大小信息

可能十几分钟都出不来结果

 

固然,第一种方法也有一些缺陷,就是当表的记录数少的时候,统计出来的每行记录占用空间是不许确的

由于datainfo这个值是以数据页大小为单位的,由于就算表只有一条记录,那么也会占用一个数据页(8KB)

那么当8KB/1 =8KB,一条记录确定不会是8KB大小的,因此记录少的时候会不许确

可是当记录数不少的时候,就准确了

 

看一下TB106这个表统计出来的结果值

SELECT AVG(DATALENGTH(C0))+AVG(DATALENGTH(C1))+AVG(DATALENGTH(C2))+AVG(DATALENGTH(C3)) FROM [dbo].[TB106]

能够看到是比较准确的

 

注意:

不管方法一仍是方法二都不包括索引所占用的空间 !!


总结

你们平时必定会想:究竟DBA有什么做用?

在这里就给你们一个例子了,在工做中,程序员是不会关心他要查询的数据的大小的,他无论三七二十一只要把数据select出来就好了,而后收工

DBA这里就要解决数据查询不出来的问题,通常的程序员以为查询500条数据是不多的,根本不会关心表设计,表的字段的数据类型

当工做愈来愈多,开发任务愈来愈重的时候更是这样



 
因此本人以为DBA这个角色仍是比较重要的o(∩_∩)o 
 
若有不对的地方,欢迎你们拍砖o(∩_∩)o 
 
 
2014-7-7 脚本bug修复
因为算出来每行记录的精度有问题,我又对脚本的精度进行了改进
CREATE TABLE #tablespaceinfo
    (
      nameinfo VARCHAR(500) ,
      rowsinfo BIGINT ,
      reserved VARCHAR(20) ,
      datainfo VARCHAR(20) ,
      index_size VARCHAR(20) ,
      unused VARCHAR(20)
    )  
 
DECLARE @tablename VARCHAR(255);  
 
DECLARE Info_cursor CURSOR
FOR
    SELECT  '[' + [name] + ']'
    FROM    sys.tables
    WHERE   type = 'U';  
 
OPEN Info_cursor  
FETCH NEXT FROM Info_cursor INTO @tablename  
 
WHILE @@FETCH_STATUS = 0
    BEGIN 
        INSERT  INTO #tablespaceinfo
                EXEC sp_spaceused @tablename  
        FETCH NEXT FROM Info_cursor  
    INTO @tablename  
    END 
 
CLOSE Info_cursor  
DEALLOCATE Info_cursor  
 
--建立临时表
CREATE TABLE [#tmptb]
    (
      TableName VARCHAR(50) ,
      DataInfo BIGINT ,
      RowsInfo BIGINT ,
      Spaceperrow  AS ( CASE RowsInfo
                         WHEN 0 THEN 0
                         ELSE CAST(DataInfo AS decimal(18,2))/CAST(RowsInfo AS decimal(18,2))
                       END ) PERSISTED
    )

--插入数据到临时表
INSERT  INTO [#tmptb]
        ( [TableName] ,
          [DataInfo] ,
          [RowsInfo]
        )
        SELECT  [nameinfo] ,
                CAST(REPLACE([datainfo], 'KB', '') AS BIGINT) AS 'datainfo' ,
                [rowsinfo]
        FROM    #tablespaceinfo
        ORDER BY CAST(REPLACE(reserved, 'KB', '') AS INT) DESC  


--汇总记录
SELECT  [tbspinfo].* ,
        [tmptb].[Spaceperrow] AS '每行记录大概占用空间(KB)'
FROM    [#tablespaceinfo] AS tbspinfo ,
        [#tmptb] AS tmptb
WHERE   [tbspinfo].[nameinfo] = [tmptb].[TableName]
ORDER BY CAST(REPLACE([tbspinfo].[reserved], 'KB', '') AS INT) DESC  

DROP TABLE [#tablespaceinfo]
DROP TABLE [#tmptb]

 

适合于不是默认架构dba的版本

--数据分析适合不是默认架构dbo
--在它的基础上作了些修改,适合不一样的框架
IF OBJECT_ID('tempdb..#TablesSizes') IS NOT NULL
    DROP TABLE #TablesSizes

CREATE TABLE #TablesSizes
    (
      TableName sysname ,
      Rows BIGINT ,
      reserved VARCHAR(100) ,
      data VARCHAR(100) ,
      index_size VARCHAR(100) ,
      unused VARCHAR(100)
    )

DECLARE @sql VARCHAR(MAX)
SELECT  @sql = COALESCE(@sql, '') + '
INSERT INTO #TablesSizes execute sp_spaceused ''' + QUOTENAME(TABLE_SCHEMA,
                                                              '[]') + '.'
        + QUOTENAME(Table_Name, '[]') + ''''
FROM    INFORMATION_SCHEMA.TABLES
WHERE   TABLE_TYPE = 'BASE TABLE'

PRINT ( @SQL )
EXECUTE (@SQL)

SELECT  *
FROM    #TablesSizes
ORDER BY Rows DESC 

 

MySQL版本

--查看每一个表大小和记录数
SELECT table_name,TABLE_ROWS,ENGINE, CONCAT(ROUND(DATA_LENGTH/1024/1024,2),'MB') AS DATA_LENGTH,
CONCAT(ROUND(INDEX_LENGTH/1024/1024,2),'MB') AS INDEX_LENGTH,
CONCAT(ROUND((INDEX_LENGTH+DATA_LENGTH)/1024/1024,2),'MB') AS TOTAL_DATASIZE
FROM information_schema.TABLES WHERE table_schema='zabbix'  ORDER BY TOTAL_DATASIZE DESC

 

 

本文版权归做者全部,未经做者赞成不得转载。

相关文章
相关标签/搜索