分享一個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

 

 

本文版權歸做者全部,未經做者贊成不得轉載。

相關文章
相關標籤/搜索