[sql-server] SQL Server에서 비트 필드를 인덱싱해야합니까?

카디널리티가 낮은 필드 (고유 값 수가 적음)를 인덱싱하는 것은 실제로 할 가치가 없다는 것을 읽은 적이 있습니다. 나는 그것이 왜인지 이해하기 위해 인덱스가 어떻게 작동하는지에 대해 충분히 알지 못한다는 것을 인정합니다.

그러면 1 억 개의 행이있는 테이블이 있고 비트 필드가 1 인 레코드를 선택하면 어떻게됩니까? 그리고 어느 시점에서나 비트 필드가 1 (0이 아닌) 인 레코드가 소수라고 가정 해 보겠습니다. 해당 비트 필드를 인덱싱 할 가치가 있습니까? 왜?

물론 테스트하고 실행 계획을 확인하는 것만으로도 할 수 있지만, 그이면의 이론도 궁금합니다. 카디널리티는 언제 중요하고 언제 중요하지 않습니까?



답변

SQL에서 인덱스가 무엇인지 고려하십시오. 인덱스는 실제로 다른 메모리 청크 (예 : 행에 대한 포인터)를 가리키는 메모리 청크입니다. 인덱스는 페이지로 나뉘어 인덱스의 일부가 사용량에 따라 메모리에서로드 및 언로드 될 수 있습니다.

행 세트를 요청할 때 SQL은 인덱스를 사용하여 테이블 스캔보다 빠르게 행을 찾습니다 (모든 행 확인).

SQL에는 클러스터형 및 비 클러스터형 인덱스가 있습니다. 클러스터형 인덱스에 대한 나의 이해는 비슷한 인덱스 값을 동일한 페이지로 그룹화한다는 것입니다. 이렇게하면 인덱스 값과 일치하는 모든 행을 요청할 때 SQL이 클러스터 된 메모리 페이지에서 해당 행을 반환 할 수 있습니다. 이것이 GUID 열의 클러스터 인덱스를 시도하는 것이 나쁜 생각 인 이유입니다. 임의의 값을 클러스터링하지 마십시오.

정수 열을 인덱싱 할 때 SQL의 인덱스에는 각 인덱스 값에 대한 행 집합이 포함됩니다. 범위가 1-10이면 인덱스 포인터가 10 개가됩니다. 얼마나 많은 행이 있는지에 따라 다르게 페이징 될 수 있습니다. 쿼리가 “1”과 일치하는 인덱스를 찾은 다음 Name에 “Fred”가 포함 된 경우 (Name 열이 인덱싱되지 않았다고 가정) SQL은 “1”과 일치하는 행 집합을 매우 빠르게 가져온 다음 테이블을 검색하여 나머지를 찾습니다.

따라서 SQL이 실제로하는 일은 반복해야하는 작업 집합 (행 수)을 줄이는 것입니다.

비트 필드 (또는 일부 좁은 범위)를 인덱싱 할 때 해당 값과 일치하는 행 수만큼만 작업 집합을 줄입니다. 일치하는 행 수가 적 으면 작업 세트가 많이 줄어 듭니다. 50/50 배포를 사용하는 많은 행의 경우 인덱스를 최신 상태로 유지하는 것보다 성능이 거의 향상되지 않을 수 있습니다.

모두가 테스트하라고 말하는 이유는 SQL이 테이블 스캔이 더 빠르다고 판단하면 인덱스를 무시하거나 정렬을 사용하거나 메모리 페이지를 구성 할 수있는 매우 영리하고 복잡한 옵티 마이저를 포함하고 있기 때문입니다.


답변

나는 다른 방법 으로이 질문을 보았습니다. 소수의 레코드 만이 1의 값을 가정한다고 가정하고 (그리고 관심있는 레코드라고 가정하면) 필터링 된 인덱스가 좋은 선택이 될 수 있습니다. 다음과 같은 것 :

create index [IX_foobar] on dbo.Foobar (FooID) where yourBitColumn = 1

이렇게하면 옵티마이 저가 쿼리에서 조건 자일 때 사용할 수있을만큼 스마트 한 인덱스가 상당히 작아집니다.


답변

비트 필드가 1로 설정된 몇 개만있는 레코드 1 억 개? 예, 비트 필드를 인덱싱하면 확실히 비트 = 1 레코드 쿼리 속도가 빨라질 것이라고 생각합니다. 인덱스에서 로그 검색 시간을 얻은 다음 비트 = 1 레코드가있는 몇 페이지 만 터치해야합니다. 그렇지 않으면 1 억 레코드 테이블의 모든 페이지를 터치해야합니다.

다시 말하지만, 저는 확실히 데이터베이스 전문가가 아니며 중요한 것을 놓칠 수 있습니다.


답변

분포가 잘 알려져 있고 불균형 한 경우 (예 : 행의 99 %가 비트 = 1이고 1 %가 비트 = 0 인 경우), 비트 = 1로 WHERE 절을 수행하면 전체 테이블 스캔이 다음과 거의 같은 시간에 수행됩니다. 인덱스 스캔. 비트 = 0 인 빠른 쿼리를 원하는 경우 가장 좋은 방법은 필터링 된 인덱스를 만들고 WHERE 비트 = 0 절을 추가하는 것입니다. 이렇게하면 해당 인덱스는 1 % 행만 저장합니다. 그런 다음 WHERE 비트 = 0을 수행하면 쿼리 옵티마이 저가 해당 인덱스를 선택하고 그로부터 모든 행이 비트 = 0이됩니다. 또한 비트의 전체 인덱스를 비교하는 데 필요한 디스크 공간이 매우 적다는 이점이 있습니다. .


답변

비트 열만 인덱싱 할 것이라고 생각하지는 않지만 복합 인덱스의 일부로 비트 열을 포함하는 것은 매우 일반적입니다.

간단한 예는 애플리케이션이 거의 항상 활성 고객을 찾을 때 성 대신 ACTIVE, LASTNAME에 대한 인덱스입니다.


답변


답변

물론 가치가 있습니다. 특히 해당 값으로 데이터를 검색해야하는 경우에는 더욱 그렇습니다. 일반 행렬을 사용하는 대신 희소 행렬을 사용하는 것과 비슷합니다.

이제 SQL 2008에서는 분할 함수를 사용할 수 있으며 인덱스에 포함되는 데이터를 필터링 할 수 있습니다. 이전 버전의 단점은 모든 데이터에 대해 인덱스가 생성된다는 점이지만 흥미로운 값을 별도의 파일 그룹에 저장하여 최적화 할 수 있습니다.