วิธีสอบถามฐานข้อมูลสำหรับตารางว่าง


28

เนื่องจาก 'นักพัฒนา' บางคนเราทำงานกับระบบของเราเรามีปัญหากับตารางที่ว่างเปล่า เราพบว่าระหว่างการถ่ายโอนไปยังคลาวด์มีการคัดลอกหลายตาราง แต่ข้อมูลในนั้นไม่ได้

ฉันต้องการเรียกใช้แบบสอบถามตารางระบบเพื่อค้นหาว่าตารางผู้ใช้ว่างเปล่า เรากำลังใช้ MS SQL 2008 R2

ขอบคุณสำหรับความช่วยเหลือ

คำตอบ:


46

เลเวอเรจsys.tablesและsys.partitions:

select
    t.name table_name,
    s.name schema_name,
    sum(p.rows) total_rows
from
    sys.tables t
    join sys.schemas s on (t.schema_id = s.schema_id)
    join sys.partitions p on (t.object_id = p.object_id)
where p.index_id in (0,1)
group by t.name,s.name
having sum(p.rows) = 0;

ใช้ผลรวมของแถวเพื่อให้แน่ใจว่าคุณไม่มีความสับสนกับตารางที่แบ่งพาร์ติชัน Index_ID เป็น 0 หรือ 1 หมายถึงคุณกำลังดูเฉพาะแถวที่นับสำหรับฮีปหรือดัชนีคลัสเตอร์


9

ดังที่ Mike Fal และ Kin ได้สังเกตเห็นทั้งสองระบบตารางเป็นเพื่อนของคุณ

สำหรับเวอร์ชันที่มีโค้ดสมบูรณ์ฉันได้ลองทำตามขั้นตอนต่อไปนี้ซึ่งจะช่วยให้คุณเห็นพื้นที่ข้อมูลทั้งหมดที่ใช้โดยแต่ละตารางในฐานข้อมูลของคุณ

USE master;

CREATE DATABASE TestDB;
GO

USE tempdb;
ALTER DATABASE TestDB SET RECOVERY SIMPLE;
GO

USE TestDB;
CREATE TABLE Test1 (
    Test1ID INT NOT NULL PRIMARY KEY IDENTITY(1,1)
    , TestData nvarchar(255) CONSTRAINT DF_Test1_TestData DEFAULT (NEWID())
);

GO

TRUNCATE TABLE Test1;

SELECT s.name + '.' + t.name AS TableName,
    sum(p.rows) AS TotalRows,
    SUM(au.data_pages) AS DataPagesUsed
FROM sys.tables t
    INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
    INNER JOIN sys.partitions p ON t.object_id = p.object_id
    INNER JOIN sys.allocation_units au ON p.hobt_id = au.container_id
WHERE au.type = 1 or au.type = 3 
    AND t.is_ms_shipped = 0
GROUP BY s.name, t.name
    ORDER BY SUM(au.data_pages) DESC;

INSERT INTO Test1 DEFAULT VALUES;

SELECT s.name + '.' + t.name AS TableName,
    sum(p.rows) AS TotalRows,
    SUM(au.data_pages) AS DataPagesUsed
FROM sys.tables t
    INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
    INNER JOIN sys.partitions p ON t.object_id = p.object_id
    INNER JOIN sys.allocation_units au ON p.hobt_id = au.container_id
WHERE au.type = 1 or au.type = 3 
    AND t.is_ms_shipped = 0
GROUP BY s.name, t.name
    ORDER BY SUM(au.data_pages) DESC;

ผลลัพธ์ของงบ 3 ล่าสุด:

ป้อนคำอธิบายรูปภาพที่นี่


6

นี่คือรุ่น PowerShell:

การใช้วัตถุการจัดการเซิร์ฟเวอร์ SQL (SMO)


function Find-EmptyTables ($server,$database) 
{

    # Load SMO assembly
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null

    $s = New-Object 'Microsoft.SqlServer.Management.Smo.Server' $server
    $db = $s.Databases.Item($database)
    $db.Tables | Where-Object { $_.RowCount -eq 0 } | Select Schema, Name, RowCount
}

ขึ้นอยู่กับจำนวนฐานข้อมูลที่คุณสามารถใช้ฟังก์ชั่นด้านบนกับรายการของชื่อฐานข้อมูลแต่ละชื่อที่บรรจุในตัวแปรและส่งออกทั้งหมดในเวลาเดียวกันหากจัดการกับเซิร์ฟเวอร์เดียว:


$DBList = 'MyDatabase1','MyDatabase2'

foreach ($d in $DBList) {
Find-EmptyTables -server MyServer -database $d | 
  Select @{Label="Database";Expression={$d}}, Schema, Name, RowCount
}

4

การตอบสนองอื่น ๆ ที่นี่ยอดเยี่ยม แต่เพื่อความสมบูรณ์: SQL Server Management Studio> คลิกขวาที่ฐานข้อมูล> รายงาน> รายงานมาตรฐาน> การใช้ดิสก์ตามตาราง


นี่จะคืนค่าตารางทั้งหมดไม่ใช่เฉพาะตารางที่ว่างเปล่า ฉันไม่เชื่อว่าคุณสามารถใช้ตัวกรองกับรายงานเหล่านั้นได้
Shawn Melton

นั่นเป็นความจริง. Pad Pad Pad
onupdatecascade

แต่มันเป็นคำตอบที่ดีมาก ระยะทางเพียงแค่ 2 คลิกง่ายกว่าที่เคย
แมเรียน

อย่างไรก็ตามคุณสามารถสั่งซื้อรายการตามจำนวนระเบียน
Robert Mikes

1

ฉันมักจะสร้างแบบสอบถามที่สร้างแบบสอบถามที่ฉันต้องการแล้วดำเนินการด้วยตนเอง แต่ถ้าคุณต้องการทั้งหมดในครั้งเดียว ...

declare @sql nvarchar(max) ;

set @sql = ';with cte as (' + (select  
        ( 
            SELECT case when row_number() 
                 over (order by table_schema, table_name) = 1 then '       ' 
                   else ' union ' end + 
                'select count(*) rws, ''[' +
                      t.TABLE_SCHEMA +'].[' + t.table_name + 
                ']'' tbl from ' + '['+ 
                      t.TABLE_SCHEMA + '].[' + TABLE_NAME + ']' + 
                CHAR(10) AS [data()] 
            FROM INFORMATION_SCHEMA.TABLES t
            FOR XML PATH ('') 
        )) + ') select * from cte where rws = 0;'

execute sp_executesql @sql;

1

ในฐานะที่เป็นคำตอบเพิ่มเติมระบบที่ไม่มีเอกสารที่จัดเก็บsp_MSforeachtableมีประโยชน์ที่นี่

CREATE TABLE #CountRows ( TableName nvarchar(260), NumRows int) ;
GO
EXEC sp_MSforeachtable 'insert into #CountRows select ''?'', count(*) from ?' ;
SELECT * FROM #CountRows WHERE NumRows = 0 ORDER BY TableName ;
DROP TABLE #CountRows ;

คำเตือนตามปกติเกี่ยวกับคุณสมบัติที่ไม่มีเอกสารใช้

คุณสามารถดูซอร์สโค้ดของโพรซีเดอร์ในต้นแบบหากคุณสงสัยหรือต้องการแน่ใจว่ามันไม่มีผลข้างเคียงที่น่ารังเกียจ มันใช้ไดนามิก SQL เพื่อสร้างเคอร์เซอร์ซึ่งไม่ดีต่อประสิทธิภาพ (cursor = slow!) ดังนั้นให้ใช้ขั้นตอนนี้สำหรับงานที่ใช้ครั้งเดียวเท่านั้น

นอกจากsp_MSforeachtableนี้ไม่สามารถใช้ได้ในฐานข้อมูล Azure


1
DECLARE @toCheck INT;
DECLARE @countoftables INT;
DECLARE @Qry NVARCHAR(100);
DECLARE @name VARCHAR(100);
BEGIN
    IF object_id('TEMPDB.DBO.#temp') IS NOT NULL drop table #temp;
    SELECT ROW_NUMBER() OVER(ORDER BY name) AS ROW,CountStatement = 'SELECT @toCheck = COUNT(*) FROM  ' + name,name INTO #temp FROM SYS.TABLES  WITH (NOLOCK)
    --SELECT * FROM #temp  ORDER BY ROW
    SET @countoftables  =(SELECT COUNT(*) FROM #temp)
    WHILE (@countoftables > 0)
        BEGIN
            SET @Qry =  (SELECT CountStatement FROM #temp  WITH (NOLOCK) WHERE ROW = @countoftables);
            SET @name = (SELECT name FROM #temp  WITH (NOLOCK) WHERE ROW = @countoftables);
            EXEC SP_EXECUTESQL @qry,N'@toCheck INT OUTPUT',@toCheck OUTPUT;
            IF(@toCheck=0)
                BEGIN
                    PRINT 'Table: ' + @name + ', count: ' +  convert(varchar(10),@toCheck);
                END
            --ELSE
            --  BEGIN
            --      PRINT 'Table: ' + @name + ', count: ' +  convert(varchar(10),@toCheck);
            --  END
            SET  @countoftables = @countoftables -1;            
        END
END

1
SELECT      T.name [Table Name],i.Rows [Number Of Rows]
FROM        sys.tables T
JOIN        sys.sysindexes I ON T.OBJECT_ID = I.ID
WHERE       indid IN (0,1) AND i.Rows<1
ORDER BY    i.Rows DESC,T.name

ฉันไม่คิดว่าวิธีนี้จะช่วยปรับปรุงคำตอบที่มีอยู่
James Anderson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.