빈 테이블에 대한 데이터베이스를 쿼리하는 방법


28

일부 '개발자'로 인해 시스템에서 작업 한 결과 빈 테이블에 문제가있었습니다. 우리는 클라우드로 전송하는 동안 여러 테이블이 복사되었지만 테이블의 데이터는 복사되지 않았다는 것을 알았습니다.

비어있는 사용자 테이블을 찾기 위해 시스템 테이블에 대한 쿼리를 실행하고 싶습니다. 우리는 MS SQL 2008 R2를 사용하고 있습니다.

도와 주셔서 감사합니다.

답변:


46

활용 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;

분할 된 테이블과 혼동되지 않도록 행 합계를 사용하십시오. 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 Server 관리 개체 (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> DB> 보고서> 표준 보고서> 테이블 별 디스크 사용량을 마우스 오른쪽 단추로 클릭하십시오.


빈 테이블뿐만 아니라 모든 테이블을 반환합니다. 해당 보고서에 필터를 적용 할 수 있다고 생각하지 않습니다.
Shawn Melton

사실입니다. 패드 패드 패드
onupdatecascade

그러나 매우 좋은 대답입니다. 2 번의 클릭 거리로 이전보다 훨씬 쉬워졌습니다.
Marian

그러나, 당신은 레코드 수에 따라 목록을 주문할 수 있습니다
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 ;

문서화되지 않은 기능에 대한 일반적인 경고가 적용됩니다.

궁금한 점이 있거나 부작용이 없는지 확인하려면 master에서 프로 시저의 소스 코드를 볼 수 있습니다. 동적 SQL을 사용하여 성능을 저하시키는 커서를 작성하므로 (cursor = slow!)이 절차는 일회성 작업에만 사용하십시오.

또한 sp_MSforeachtableAzure Database에서는 사용할 수 없습니다.


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.