Cara kueri database untuk tabel kosong

28

Karena beberapa 'pengembang' kami telah mengerjakan sistem kami, kami memiliki masalah dengan tabel kosong. Kami telah menemukan bahwa selama transfer ke cloud beberapa tabel disalin, tetapi data di dalamnya tidak.

Saya ingin menjalankan kueri tabel sistem untuk menemukan tabel pengguna apa yang kosong. Kami menggunakan MS SQL 2008 R2.

Terima kasih untuk bantuannya.

pembuat kode
sumber

Jawaban:

46

Leverage sys.tablesdan 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;

Gunakan jumlah baris hanya untuk memastikan Anda tidak memiliki kebingungan dengan tabel yang dipartisi. Index_ID dari 0 atau 1 berarti Anda hanya melihat jumlah baris untuk tumpukan Anda atau indeks berkerumun.

Mike Fal
sumber
9

Seperti yang dicatat oleh Mike Fal dan Kin, tabel sistem adalah teman Anda.

Untuk versi yang lebih lengkap dengan kode, saya datang dengan yang berikut, yang akan memungkinkan Anda untuk melihat total ruang data yang digunakan oleh setiap tabel di database Anda.

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;

Hasil dari 3 pernyataan terakhir:

masukkan deskripsi gambar di sini

Max Vernon
sumber
6

Ini adalah versi PowerShell:

Menggunakan SQL Server Management Objects (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
}

Bergantung pada jumlah basis data Anda dapat menggunakan fungsi di atas terhadap daftar setiap nama basis data yang dihuni dalam suatu variabel dan mengeluarkan semuanya pada saat yang bersamaan, jika berurusan dengan satu server:


$DBList = 'MyDatabase1','MyDatabase2'

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

Respons lain di sini luar biasa, tetapi untuk kelengkapan: SQL Server Management Studio> klik kanan DB> Laporan> Laporan Standar> Penggunaan Disk oleh Tabel

onupdatecascade
sumber
Ini akan mengembalikan semua tabel, bukan hanya yang kosong. Saya tidak percaya Anda dapat menerapkan filter pada laporan tersebut.
Shawn Melton
Itu benar. Pad Pad Pad
onupdatecascade
Tapi itu jawaban yang sangat bagus. Hanya pada jarak 2 klik, lebih mudah dari sebelumnya.
Marian
Namun, Anda dapat memesan daftar berdasarkan jumlah catatan
Robert Mikes
1

Saya biasanya hanya membuat kueri yang membuat kueri yang saya inginkan dan kemudian menjalankannya secara manual, tetapi jika Anda ingin semuanya sekaligus ...

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;
jmoreno
sumber
1

Sebagai jawaban tambahan, prosedur tersimpan sistem tidak berdokumen sp_MSforeachtableberguna di sini.

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 ;

Peringatan biasa tentang fitur tidak berdokumen berlaku.

Anda dapat melihat kode sumber prosedur di master jika Anda penasaran atau jika Anda ingin memastikan itu tidak memiliki efek samping yang buruk. Ini menggunakan SQL dinamis untuk membangun kursor, yang buruk untuk kinerja (kursor = lambat!), Jadi hanya gunakan prosedur ini untuk tugas satu kali.

Selain itu, sp_MSforeachtabletidak tersedia di Azure Database.

Greenstone Walker
sumber
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
Dinesh Ramaian
sumber
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
Pavan Kumar Gupta
sumber
Saya tidak berpikir ini membaik pada jawaban yang ada
James Anderson