Cách truy vấn cơ sở dữ liệu cho các bảng trống


28

Do một số 'nhà phát triển, chúng tôi đã làm việc trên hệ thống của mình, chúng tôi đã gặp sự cố với các bảng trống. Chúng tôi đã thấy rằng trong quá trình chuyển sang đám mây, một số bảng đã được sao chép, nhưng dữ liệu trong đó thì không.

Tôi muốn chạy một truy vấn các bảng hệ thống để tìm những gì bảng người dùng trống. Chúng tôi đang sử dụng MS SQL 2008 R2.

Cảm ơn đã giúp đỡ.

Câu trả lời:


46

Đòn bẩy sys.tablessys.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;

Sử dụng tổng số hàng chỉ để đảm bảo bạn không nhầm lẫn với các bảng được phân đoạn. Index_ID là 0 hoặc 1 có nghĩa là bạn chỉ nhìn vào số hàng cho các đống hoặc chỉ mục được nhóm của bạn.


9

Như Mike Fal và Kin đều lưu ý, các bảng hệ thống là bạn của bạn.

Để có phiên bản hoàn chỉnh hơn về mã, tôi đã đưa ra các điều sau đây, điều này sẽ cho phép bạn xem tổng không gian dữ liệu được sử dụng bởi mỗi bảng trong cơ sở dữ liệu của bạn.

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;

Kết quả của 3 tuyên bố cuối cùng:

nhập mô tả hình ảnh ở đây


6

Đây là phiên bản PowerShell:

Sử dụng các đối tượng quản lý máy chủ 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
}

Tùy thuộc vào số lượng cơ sở dữ liệu, bạn có thể sử dụng chức năng trên đối với danh sách từng tên cơ sở dữ liệu được điền trong một biến và xuất tất cả cùng một lúc, nếu giao dịch với một máy chủ:


$DBList = 'MyDatabase1','MyDatabase2'

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

4

Các phản hồi khác ở đây rất tuyệt, nhưng để hoàn thiện: SQL Server Management Studio> nhấp chuột phải vào DB> Báo cáo> Báo cáo chuẩn> Sử dụng đĩa theo bảng


Điều này sẽ trả về tất cả các bảng mặc dù, không chỉ những bảng trống. Tôi không tin rằng bạn có thể áp dụng các bộ lọc cho các báo cáo đó.
Shawn Melton

Điều đó đúng. Pad Pad Pad
onupdatecascade

Nhưng đó là một câu trả lời rất tốt. Chỉ với khoảng cách 2 lần nhấp, dễ dàng hơn bao giờ hết.
Thánh Mẫu

Tuy nhiên, bạn có thể sắp xếp danh sách theo số lượng hồ sơ
Robert Mikes

1

Tôi thường chỉ tạo một truy vấn tạo truy vấn mà tôi muốn và sau đó thực hiện thủ công, nhưng nếu bạn muốn tất cả trong một lần ...

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

Như một câu trả lời bổ sung, thủ tục lưu trữ hệ thống không có giấy tờ sp_MSforeachtablerất hữu ích ở đây.

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 ;

Các cảnh báo thông thường về các tính năng không có giấy tờ được áp dụng.

Bạn có thể xem mã nguồn của quy trình trong master nếu bạn tò mò hoặc nếu bạn muốn chắc chắn nó không có tác dụng phụ khó chịu. Nó sử dụng SQL động để xây dựng một con trỏ, điều này không tốt cho hiệu năng (con trỏ = chậm!), Vì vậy chỉ sử dụng quy trình này cho một nhiệm vụ một lần.

Ngoài ra, sp_MSforeachtablekhông có sẵn trong Cơ sở dữ liệu 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

Tôi không nghĩ rằng điều này sẽ cải thiện các câu trả lời hiện có
James Anderson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.