데이터베이스에서 모든 테이블의 압축되지 않은 크기 찾기


12

Dynamics AX에는 테이블을 메모리에로드하고 캐시하도록 구성 할 수있는 캐싱 메커니즘이 있습니다. 이 캐시는 메모리 문제를 방지하기 위해 특정 양의 KB로 제한됩니다. 내가 말하고있는 설정이 호출 entiretablecache되고 단일 레코드가 요청되는 즉시 전체 테이블을 메모리에로드합니다.

최근까지이 설정이있는 테이블의 크기를 확인하여 테이블 크기가이 제한을 초과하는지 확인하기 위해 일부 스크립트를 사용했습니다.

그러나 이제 압축이 시작되고 sp_spaceused 또는 sys.allocation_units 와 같은 것이 압축 된 데이터에서 실제로 사용 된 공간을보고하는 것 같습니다.

분명히 응용 프로그램 서버는 압축되지 않은 데이터로 작업하므로 SQL Server의 디스크에있는 데이터 크기는 관련이 없습니다. 압축되지 않은 데이터의 실제 크기가 필요합니다.

sp_estimate_data_compression_savings는 알고 있지만 이름에서 알 수 있듯이 이는 추정치 일뿐입니다.
가능한 한 정확한 크기를 선호합니다.

내가 생각할 수있는 유일한 방법은 압축 된 테이블과 동일한 구조로 압축되지 않은 테이블을 작성하고 해당 새도우 테이블에 압축 된 데이터를 삽입 한 다음 해당 새도우 테이블의 크기를 확인하는 복잡한 동적 SQL이었습니다.
말할 것도없이, 이것은 약간 지루하며 수백 GB의 데이터베이스에서 실행하는 데 시간이 걸립니다.

Powershell은 옵션이 될 수 있지만 모든 테이블을 반복 select *하여 스크립트에서 크기를 확인 하기 위해 모든 테이블을 반복하고 싶지는 않습니다 . 캐시가 쇄도하고 시간이 오래 걸릴 수 있기 때문입니다.

간단히 말해서, 각 테이블의 크기를 한 번 압축하지 않고 가능한 경우 응용 프로그램에 표시된 방정식에서 조각화하여 크기를 얻는 방법이 필요합니다. 나는 다른 접근 방식에 개방적이며 T-SQL이 선호되지만 Powershell 또는 다른 창조적 인 접근 방식에는 반대하지 않습니다.

응용 프로그램의 버퍼가 데이터의 크기라고 가정하십시오. bigint는 항상 bigint의 크기이며 문자 데이터 유형은 문자 당 2 바이트 (유니 코드)입니다. BLOB 데이터는 데이터 크기도 사용하며, 열거 형은 기본적으로 int이고 숫자 데이터는 숫자 (38,12), datetime은 날짜 / 시간의 크기입니다. 또한 NULL값 이 없으며 빈 문자열로 저장 1900-01-01되거나 0입니다.

이것이 어떻게 구현되는지에 대한 문서는 없지만 가정은 PFE와 지원 팀이 사용하는 일부 테스트 및 스크립트를 기반으로합니다 (검사는 응용 프로그램에 내장되어 있으며 응용 프로그램에서 알 수 없으므로 압축을 무시합니다) 기본 데이터가 압축되어 있으면 테이블 크기도 확인합니다. 이 링크 의 예는 다음과 같습니다.

큰 테이블에 대해서는 WholeTable 캐시를 사용하지 마십시오 (AX 2009에서는 128KB 또는 16 페이지 이상, AX 2012에서는 '전체 테이블 캐시 크기'응용 프로그램 설정 [기본값 : 32KB 또는 4 페이지]) – 대신 레코드 캐싱으로 이동하십시오.


3
해 키지 만 압축이 비활성화 된 복원 사본이 가장 정확할 것입니다. 그런 다음 복원도 테스트하여 TOP 1 DBA처럼 보입니다.
Erik Darling

그것이 최선의 방법이라고 생각하십시오. 수학을 시도하고 수행하는 방법이있을 수 있습니다. 정의 된 컬럼 데이터 유형 및 길이에 곱한 행 수를 곱한 다음 인덱스 등을 추가하십시오. 복원 스크립트를 작성하고 압축을 비활성화하는 것보다 위의 @sp_BlitzErik이 제안하는 것보다 훨씬 많은 작업이 있습니다. 그리고 TOP 1 DBA가되고 싶지 않은 사람은 누구입니까?
Mike Walsh

모든 열에 대한 SUM (datalength ())은 압축되지 않은 데이터 크기를 얻습니까?
Tapakah Ua

@sp_BlitzErik 댓글 대신 답이 될 수 있습니다.
톰 V - topanswers.xyz 시도

답변:


7

압축되지 않은 데이터의 실제 크기가 필요합니다.
...
가능한 한 정확한 크기를 선호합니다.

이 정보에 대한 열망은 확실히 이해할 만하지 만, 특히 "가능한 한 올바른 것"이라는 맥락에서이 정보를 얻는 것은 잘못된 가정으로 인해 모든 사람이 기대하는 것보다 까다 롭습니다. 질문에 언급 된 압축되지 않은 섀도우 테이블 아이디어를 수행하든, DB 복원 및 압축 해제에 대한 주석에서 @sp_BlitzErik의 제안을 수행하든, 압축되지 않은 테이블의 크기 == 메모리에서 상기 데이터의 크기라고 가정해서는 안됩니다 앱 서버에서 :

  1. 있습니까 모든 테이블의 행은 캐시되는? 아니면 그냥 범위 내에 있습니까? 여기에서의 가정은 그것이 전부이고 맞을 수도 있지만, 이것이 사실이 아닐 수도 있다고 언급해야한다고 생각했습니다 . 언급되지 않아야 함).

    질문이 상태로 업데이트되었습니다. 예, 모든 행이 캐시됩니다.

  2. 구조 오버 헤드

    1. DB 쪽 : DB 쪽의
      페이지 및 행 오버 헤드 : 페이지에 맞는 행 수는 예상치를 버릴 수있는 여러 요인에 의해 결정됩니다. 심지어로 FILLFACTOR100 (또는 0)의, 그것 때문에 전체 행에 대한 충분한되지 않는 여전히 가능성이 일부 사용되지 않는 공간이 페이지에 남아있을 것입니다. 그리고 그것은 페이지 헤더에 추가됩니다. 또한 Snapshot Isolation 기능이 활성화되면 버전 번호에 따라 행당 13 바이트가 추가되어 예상치를 버릴 것이라고 생각합니다. 행의 실제 크기 (NULL 비트 맵, 가변 길이 열 등)와 관련된 다른 세부 사항이 있지만 지금까지 언급 한 항목만으로도 포인트가됩니다.
    2. 앱 서버 측 :
      캐시 된 결과를 저장하는 데 사용되는 컬렉션 유형은 무엇입니까? 나는 이것이 .NET 응용 프로그램이라고 가정합니다 DataTable. 일반 목록? 정렬 된 사전? 각 컬렉션 유형에는 다른 양의 오버 헤드가 있습니다. 필자는 DB 측면에서 특히 페이지 및 행 오버 헤드를 반드시 반영 할 수있는 옵션을 기대하지 않을 것입니다. 수백 바이트 또는 몇 kB).
  3. 자료형
    1. DB 쪽 :
      CHAR/ VARCHAR데이터는 문자 당 1 바이트로 저장됩니다 (현재 2 바이트 문자는 무시). XML텍스트 표현에서 알 수 있듯이 공간을 거의 차지하지 않도록 최적화되었습니다. 이 데이터 유형은 요소 및 속성 이름의 사전을 작성하고 문서에서 이들에 대한 실제 참조를 각각의 ID (실제로 친절)로 대체합니다. 그렇지 않으면 문자열 값은 NCHAR/ 와 마찬가지로 모두 UTF-16 ( "문자"당 2 또는 4 바이트) NVARCHAR입니다. DATETIME26에서 8 바이트 사이입니다. DECIMAL정밀도에 따라 5에서 17 바이트 사이입니다.
    2. 앱 서버 측에서 :
      문자열 (다시 .NET이라고 가정)은 항상 UTF-16입니다. VARCHAR보유하고있는 것과 같은 8 비트 문자열에 대한 최적화는 없습니다 . 그러나 문자열은 여러 번 참조 할 수있는 공유 사본 인 "interned"일 수도 있습니다 (그러나 이것이 컬렉션의 문자열에서 작동하는지 또는 모든 유형의 컬렉션에서 작동하는 경우 모르겠습니다). XML메모리에 같은 방식으로 저장되거나 저장되지 않을 수 있습니다 (이를 찾아야합니다). DateTime8 (T-SQL과 같은 바이트 항상 DATETIME있지만처럼 DATE, TIME또는은 DATETIME2). Decimal이다 항상 16 바이트 .

말하자면 , 앱 서버 측에서 상당히 정확한 메모리 풋 프린트 크기 를 얻기 위해 DB 측에서 할 수있는 일은 거의 없습니다 . 특정 테이블이로드 된 후 앱 서버 자체를 조사 할 수있는 방법을 찾아야합니다. 그리고 디버거가 채워진 컬렉션의 런타임 크기를 볼 수 있는지 확실하지 않습니다. 그렇지 않은 경우 가까이 접근하는 유일한 방법은 테이블의 모든 행을 통과하여 각 열에 적절한 .NET 크기 (예 : INT= * 4, VARCHAR= DATALENGTH() * 2, NVARCHAR= DATALENGTH(), XML= 🙃 등)를 곱하는 것이지만 여전히 질문을 남깁니다. 컬렉션의 오버 헤드와 컬렉션의 각 요소.

질문에 새로운 정의가 주어지면 아마도 다음 쿼리를 수행하여 다소 가까워 질 수 있습니다. 그리고 테이블이 압축되었는지 여부는 중요하지 않지만 프로덕션에서 모든 행을 스캔하는 것이 적절한 지 여부를 결정하는 것은 각 사람의 몫입니다 (복원 또는 사용량이 적은 시간에 가능).

SELECT
   SUM( DATALENGTH([NVarcharColumn_1]) + DATALENGTH([NVarcharColumn_N]) ) + 
   SUM( (DATALENGTH([VarcharColumn_1]) + DATALENGTH([VarcharColumn_N])) * 2 ) + 
   SUM(4 * [number_of_INT_columns]) +
   SUM(8 * [number_of_BIGINT_and_DATETIME_columns]) +
   SUM(16 * [number_of_DECIMAL/NUMERIC_and_UNIQUEIDENTIFIER_columns]) +
   etc..
FROM [SchemaName].[TableName] WITH (NOLOCK) -- assuming no Snapshot Isolation

그러나 이것은 컬렉션 또는 컬렉션 요소 오버 헤드를 설명하지 않습니다. 디버거 (또는 ILSpy와 같은 것)없이 그 가치를 얻을 수 있는지 확실하지 않지만 현지 법률에 따라 EULA를 위반 할 있으므로 권장하지 않습니다 .


우리는 애플리케이션에 제시된 버퍼 크기를 확인하기 위해 코드에서 검사를 구현했습니다.
톰 V - topanswers.xyz 시도

6

귀하의 질문 S에 따르면 최대 캐시 크기가 있고 해당 크기를 초과하는 캐시에 테이블을로드하지 않으려 는 것처럼 보입니다 . 이것이 사실이라면 각 테이블의 정확한 크기를 알 필요가 없습니다. 테이블이 최대 캐시 크기보다 크거나 작은 지 알아야합니다 S. 이는 테이블의 열 정의 및 행 수에 따라 훨씬 쉬운 문제입니다.

압축되지 않은 데이터를 보는 것이 좋은 방법이 아니며 캐시에있는 테이블의 실제 크기에 대한 근사치를 구하기가 어렵다는 점에서 Solomon Rutzky의 큰 대답에 동의합니다. 그러나 질문의 ​​프레임 워크 내에서 작업하고 정적 데이터 유형에 대한 열 정의와 동적 열의 실제 길이를 기반으로 충분히 가까운 수식을 개발할 수 있다고 가정합니다.

데이터 유형을 캐시 크기에 맵핑하는 경우 데이터를 보지 않고도 일부 테이블을 평가할 수 있어야합니다.

  1. 테이블에 정적 데이터 유형 (문자열 또는 블롭 없음) 만있는 경우 sys.partitions열 정의를 사용하여 테이블 크기를 보고 계산하여 행 수를 근사화 할 수 있습니다.
  2. 많은 행이있는 테이블에 충분한 정적 데이터 유형 열이있는 경우 데이터를 보지 않고 너무 큰 테이블을 제거 할 수 있습니다. 예를 들어, 1 천만 개의 행과 5 개의 BIGINT열이 있는 테이블 의 데이터 크기는 10000000 * (8 + 8 + 8 + 8 + 8) = 400M 바이트이며 캐시 크기 제한보다 클 수 있습니다 S. 문자열 열이 많더라도 중요하지 않습니다.
  3. 행 수가 적은 테이블이 충분히 작은 경우 각 동적 데이터 유형에 가능한 최대 크기가 있다고 가정하여 단순히 한계 미만인지 확인할 수 있습니다. 예를 들면, 100 행으로 나타난 BIGINT열 및 NVARCHAR(20)컬럼 (100) * (2 * 8 + 20) = 4800 바이트를 초과 할 수있다.
  4. SQL Server에서 테이블에 압축 된 크기가 S있는 경우 캐시에 맞지 않을 가능성이 매우 큰 것이 사실 일 수 있습니다 . 이러한 값이 존재하는지 확인하기 위해 테스트를 수행해야합니다.
  5. 모든 동적 열에 통계가 있다는 점에서 운이 좋을 수 있습니다. 통계에는 평균 길이에 대한 정보가 포함되며 이는 귀하의 목적에 충분히 정확할 수 있습니다.

위의 기준에 맞지 않는 테이블의 데이터를 쿼리해야 할 수도 있습니다. 이것의 성능 영향을 최소화하기 위해 사용할 수있는 몇 가지 트릭이 있습니다. 여기에는 두 가지 경쟁 우선 순위가 있습니다. 정확성을 중요하게 생각하지만 데이터베이스의 모든 데이터를 스캔하고 싶지는 않습니다. 계산에 일종의 버퍼를 추가 할 수 있습니다. 최대 캐시 크기보다 약간 작은 테이블을 제외 S하거나 최대 캐시 크기보다 약간 큰 테이블을 포함시키는 것이 더 허용 가능한지 모르겠습니다 .

다음은 테이블 데이터를보다 빠르게 보는 쿼리를 만들기위한 몇 가지 아이디어입니다.

  1. 큰 테이블 TABLESAMPLE의 경우 샘플 크기가 충분히 크면 사용할 수 있습니다.
  2. 클러스터 키가있는 큰 테이블의 경우 클러스터 키에서 배치로 처리하는 것이 유용 할 수 있습니다. 불행히도 나는 SUM()그 집계의 가치에 따라 일찍 종료 하는 계산 방법을 모른다 . 나는 그 일을 본 적이있다 ROW_NUMBER(). 그러나 테이블의 처음 10 %를 스캔하고 계산 된 데이터 크기를 저장하고 다음 10 %를 스캔하는 등의 작업을 수행 할 수 있습니다. 캐시에 비해 너무 큰 테이블의 경우 일찍 종료하여이 방법으로 상당한 양의 작업을 절약 할 수 있습니다.
  3. 일부 테이블의 경우 모든 동적 열에서 인덱스를 포함 할만큼 운이 좋을 수 있습니다. 행 크기 또는 한 번에 각 인덱스를 스캔하는 다른 요소에 따라 테이블 스캔을 수행하는 것보다 빠를 수 있습니다. 단일 열에서 인덱스를 읽은 후 테이블 크기가 너무 큰 경우이 프로세스를 일찍 종료 할 수도 있습니다.
  4. 동적 열의 평균 길이는 시간이 지나도 크게 변하지 않을 수 있습니다. 계산하는 평균 길이를 저장하고 계산에 이러한 값을 잠시 사용하는 것이 실용적 일 수 있습니다. 테이블의 DML 활동 또는 다른 메트릭을 기반으로이 값을 재설정 할 수 있습니다.
  5. 알고리즘을 개발하기 위해 모든 테이블에 대해 테스트를 실행할 수있는 경우 데이터의 패턴을 활용할 수 있습니다. 예를 들어, 가장 작은 것부터 시작하여 테이블을 처리하면 캐시에 비해 너무 큰 행에서 10 개 (이 숫자를 만든) 테이블을 처리 한 후에는 더 큰 테이블이 은닉처. 캐시에 적합 할 수있는 몇 개의 테이블을 제외해도 괜찮을 수 있습니다.

이 답변에 SQL 코드가 포함되어 있지 않다는 것을 알고 있습니다. 여기서 논의한 아이디어에 대한 데모 코드를 작성하는 것이 도움이되는지 알려주십시오.


2
나는 그런 제외한 테이블의 접근 생각하지 않았다, 나는 접근 방식 등
톰 V - topanswers.xyz 시도
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.