Boş tablolar için bir veritabanı nasıl sorgulanır


28

Bazı 'geliştiriciler' nedeniyle sistemimiz üzerinde çalıştığımız için boş masa sorunlarımız vardı. Buluta geçişte birkaç tablo kopyalandığını gördük, ancak içlerindeki veriler değildi.

Hangi kullanıcı tablolarının boş olduğunu bulmak için sistem tablolarını sorgulamak istiyorum. MS SQL 2008 R2 kullanıyoruz.

Yardım için teşekkürler.

Yanıtlar:


46

Kaldıraç sys.tablesve 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;

Bölümlenmiş tablolarla ilgili karışıklığınızın olmadığından emin olmak için bir satır toplam kullanın. 0 veya 1 değerinin Index_ID değeri, yığınlarınız veya kümelenmiş dizinleriniz için yalnızca satır sayılarına baktığınız anlamına gelir.


9

Mike Fal ve Kin'in de belirttiği gibi, sistem tabloları senin arkadaşın.

Daha fazla kod içeren bir sürüm için, aşağıdakileri kullandım; bu, veritabanındaki her tablo tarafından kullanılan toplam veri alanını görmenizi sağlar.

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;

Son 3 ifadenin sonuçları:

görüntü tanımını buraya girin


6

İşte PowerShell sürümü:

SQL Server Yönetim Nesnelerini (SMO) Kullanma


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
}

Veritabanlarının sayısına bağlı olarak, yukarıdaki işlevi, bir değişkende bulunan her veritabanı adının bir listesine karşı kullanabilir ve bir sunucu ile ilgileniyorsanız hepsini aynı anda çıkarabilirsiniz:


$DBList = 'MyDatabase1','MyDatabase2'

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

4

Buradaki diğer yanıtlar mükemmeldir, ancak eksiksiz olması için: SQL Server Management Studio> DB> Raporlar> Standart Raporlar> Tabloya Göre Disk Kullanımı'nı sağ tıklatın


Bu, yalnızca boş olanları değil tüm tabloları döndürür. Bu raporlara filtre uygulayabileceğinizi sanmıyorum.
Shawn Melton

Bu doğru. Pad Pad Pad
onupdatecascade 13:13

Ama bu çok iyi bir cevap. Sadece 2 tıklama mesafesinde, her zamankinden daha kolay.
Marian,

Ancak, listeyi kayıt sayısına göre sipariş edebilirsiniz
Robert Mikes

1

Genelde sadece istediğim sorguyu yaratan bir sorgu oluşturur ve bunu manuel olarak çalıştırırım, ancak hepsini bir arada yapmak istiyorsanız ...

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

Ek bir cevap olarak, belgelenmemiş sistem saklı yordamı sp_MSforeachtableburada yararlıdır.

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 ;

Belgelenmemiş özelliklerle ilgili olağan uyarılar geçerlidir.

Merak ediyorsanız veya herhangi bir kötü yan etkisi olmadığından emin olmak istiyorsanız, ustadaki prosedürün kaynak koduna bakabilirsiniz. Performans için kötü olan bir imleç oluşturmak için dinamik SQL kullanır (imleç = yavaş!), Bu yüzden sadece bir kerelik görev için bu prosedürü kullanın.

Ayrıca, sp_MSforeachtableAzure Veritabanında mevcut değildir.


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

Bunun mevcut cevapları iyileştirdiğini sanmıyorum
James Anderson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.