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.