SQL Server 시스템 테이블을 조각 모음 할 수 있습니까?


15

우리는 많은 수의 테이블이 생성되고 삭제되는 여러 데이터베이스를 가지고 있습니다. 우리가 알 수 있듯이 SQL Server는 시스템 기본 테이블 에 대한 내부 유지 관리를 수행하지 않으므로 시간이 지남에 따라 매우 조각화되고 크기가 커질 수 있습니다. 이는 버퍼 풀에 불필요한 압력을 가하고 데이터베이스의 모든 테이블 크기 계산과 같은 조작 성능에 부정적인 영향을 미칩니다.

이 핵심 내부 테이블에서 조각화를 최소화하기위한 제안이 있습니까? 한 가지 확실한 해결책은 너무 많은 테이블을 만들지 않거나 tempdb에 모든 임시 테이블을 만드는 것을 피할 수 있지만이 질문의 목적을 위해 응용 프로그램에 유연성이 없다고 가정 해 봅시다.

편집 : 추가 연구에 따르면이 답변되지 않은 질문 은 밀접하게 관련되어 있으며 수동 유지 관리의 일부 형식이 ALTER INDEX...REORGANIZE옵션 일 수 있음을 나타냅니다 .


초기 연구

이 테이블에 대한 메타 데이터는 다음에서 볼 수 있습니다 sys.dm_db_partition_stats.

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136

그러나 sys.dm_db_index_physical_stats이러한 테이블의 조각화보기를 지원하지 않는 것 같습니다.

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
    DB_ID(),
    OBJECT_ID('sys.syscolpars'),
    NULL,
    NULL,
    'DETAILED'
)

Ola Hallengren의 스크립트 에는 is_ms_shipped = 1객체의 조각 모음을 고려하는 매개 변수도 포함되어 있지만이 매개 변수를 활성화해도 시스템 기본 테이블은 자동으로 무시됩니다. 올라 (Ola)는 이것이 예상되는 행동이라고 설명했다. ms_shipped (예 :) 인 사용자 테이블 (시스템 테이블 아님 msdb.dbo.backupset) 만 고려됩니다.

-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
        @FragmentationLow = 'INDEX_REORGANIZE',
        @FragmentationMedium = 'INDEX_REORGANIZE',
        @FragmentationHigh = 'INDEX_REORGANIZE',
        @PageCountLevel = 0,
        @UpdateStatistics = 'ALL',
        @Indexes = '%Test.sys.sysrowsets.%',
        -- Proc works properly if targeting a non-system table instead
        --@Indexes = '%Test.dbo.Numbers.%',
        @MSShippedObjects = 'Y',
        @Execute = 'N';
PRINT(@result);


추가 요청 정보

inspect 시스템 테이블 버퍼 풀 사용 아래에서 Aaron의 쿼리를 적용하여 하나의 데이터베이스에 대한 버퍼 풀에 수십 GB의 시스템 테이블이 있으며 그 경우 공간의 ~ 80 %가 여유 공간이라는 것을 알았습니다. .

-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
    COUNT(b.page_id) pages,
    SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
    ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
    ON p.partition_id = a.container_id
    AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC

여기에 이미지 설명을 입력하십시오

답변:


11

이 시스템 테이블을 "버퍼 풀에 대한 불필요한 압력의 유일한 소스로 식별하고 데이터베이스의 모든 테이블 크기 계산과 같은 작업의 성능에 부정적인 영향을 미칩니다"라고 확실하고 정확하게 알고 있습니까? 이 시스템 테이블이 (a) 조각화가 최소화되거나 비밀리에 확인되거나 또는 (b) 메모리에서 효율적으로 관리되어 조각 모음 수준이 실제로 큰 영향을 미치지 않는 방식으로 자체 관리되지 않습니까?

당신은 사용에 얼마나 많은 페이지를 볼 수 있습니다, 당신은 얼마나 많은 여유 공간이 것은에 볼 수 있습니다 메모리에있는 페이지 ( page_free_space_percent항상 NULL할당 된 메모리 DMF에, 그러나 이것은 이다 버퍼 DMV에서 사용 가능) -이 당신에게 몇 가지 아이디어를 줄 것이다 당신이 걱정하는 것이 정말로 걱정해야 할 것이 있다면 :

SELECT 
  Number_of_Pages = COUNT(*), 
  Number_of_Pages_In_Memory = COUNT(b.page_id),
  Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0) 
FROM sys.dm_db_database_page_allocations
(
  DB_ID(),
  OBJECT_ID(N'sys.syscolpars'),
  NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID() 
AND b.page_id = p.allocated_page_page_id 
AND b.file_id = p.allocated_page_file_id;

페이지 수가 적거나 (시스템 테이블의 경우 <10000과 같이) 여유 공간이 "낮음"(일반적인 임계 값이 재구성 / 재 구축에 대한 것인지 확실하지 않은 경우) 인 경우 더 흥미롭고 덜 거칠고 다른 과일에 집중 .

페이지의 전화 번호가 큰 경우 및 여유 공간이 "높은"입니다, 좋아, 어쩌면 나는 자신의 자체 유지 보수를 위해 SQL 서버 너무 많은 신용을주고있다. 다른 질문 에서 알 수 있듯이 이것은 작동합니다 ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... 그리고 하지 단편화를 줄일 수 있습니다. 높은 권한이 필요할 수 있지만 (나는 peon으로 시도하지 않았습니다).

기분이 좋거나 시스템에 전혀 긍정적 인 영향을 미친다는 증거가 있다면 유지 관리의 일환으로이 작업을 주기적으로 수행 할 수 있습니다.


우리가 한 일을 요약 한 다른 대답을 추가 한 다음 여기에서 이전 의견을 정리했습니다. 도와 주셔서 감사합니다!
— Geoff Patterson

7

Aaron의 답변과 추가 연구를 바탕으로 내가 취한 접근 방식에 대한 빠른 글을 작성했습니다.

내가 알 수 있듯이 시스템 기본 테이블의 조각화를 검사하는 옵션은 제한되어 있습니다. 계속 해서 Connect 문제를 제기 했습니다 더 나은 가시성을 제공하기 위해 를 했지만 그 동안 옵션에는 버퍼 풀 검사 또는 행당 평균 바이트 수 확인과 같은 항목이 포함 된 것으로 보입니다.

그런 다음 모든 시스템 기본 테이블에서`ALTER INDEX ... REORGANIZE를 수행 하는 프로 시저를 작성했습니다. . 가장 많이 사용 된 dev 서버 중 일부에서이 절차를 실행하면 시스템 기본 테이블의 누적 크기가 최대 50GB (시스템의 ~ 5MM 사용자 테이블과 함께 극단적 인 경우)로 트리밍 된 것으로 나타났습니다.

다양한 단위 테스트 및 개발로 생성 된 많은 사용자 테이블을 정리하는 데 도움이되는 야간 야간 유지 관리 작업 중 하나는 이전에 ~ 50 분이 소요되었습니다. 의 조합 sp_whoisactive, sys.dm_os_waiting_tasks그리고 DBCC PAGE기다려야 함이 시스템 기본 테이블에 I / O에 의해 지배 된 것으로 나타났다.

모든 시스템 기본 테이블을 재구성 한 후 유지 관리 작업이 ~ 15 분으로 떨어졌습니다. 여전히 일부 I / O 대기가 있었지만 캐시에 남아있는 데이터의 양이 많고 조각화가 적어 판독 헤드가 많기 때문에 상당히 줄었습니다.

따라서 필자의 결론은 ALTER INDEX...REORGANIZE시스템 기본 테이블을 유지 관리 계획에 추가 하는 것이 고려해야 할 유용한 정보 일 수 있지만 데이터베이스에 비정상적인 수의 개체가 생성되는 시나리오가있는 경우에만 가능합니다.


질문과 대답 모두 +1 - 내부는 블랙 박스의 비트, 그리고 당신은 성능을 위해 정말 불쾌한 시나리오 (당신이 경우에도 어떻게 생겼는지에 도움이 되거 도왔 입니다 가장자리의 경우).
— Max Vernon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.