SQL Server에서 비트 필드를 인덱싱해야합니까?


99

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

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

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


이것은 일반적인 쿼리입니까? "소수"의 레코드를 찾을 때 그만한 가치가 있지만 다른 행에서는 그다지 도움이되지 않습니다. 데이터를 식별하는 다른 방법이 있습니까?
jason saldo

4
비트 열만 인덱싱 할 것이라고 생각하지는 않지만 복합 인덱스의 일부로 비트 열을 포함하는 것은 매우 일반적입니다. 간단한 예는 애플리케이션이 거의 항상 활성 고객을 찾을 때 성 대신 ACTIVE, LASTNAME에 대한 인덱스입니다.
BradC

"카디널리티가 낮은 필드 (고유 값 수가 적음)를 인덱싱하는 것은 실제로 할 가치가 없다는 것을 한 시점에서 읽은 것을 기억합니다."SQL Server는 거의 항상 테이블 스캔을 수행하는 것보다 인덱스. 따라서 기본적으로 인덱스는 사용되지 않으며 유지 관리하는 것은 낭비입니다. 다른 사람들이 말했듯이 복합 지수에서는 괜찮을 수 있습니다.
DJ.

5
동의하지 않습니다. 배포가 50/50이면 테이블 스캔을 수행하는 것이 더 빠르기 때문에 인덱스를 사용하지 않습니다. 그러나 값이 5 개, 1 개, 0 개인 경우 1을 검색 할 때 인덱스를 사용할 가능성이 매우 높습니다.
Kibbee

1
당신이 준 예에서, 나는 LastName을 먼저 넣는 경향이 있습니다. 특정 쿼리 워크로드에 따라 다르지만 일반적으로 더 선택적인 열을 먼저 사용하면 인덱스를 사용할 가능성이 더 높습니다.
Mitch Wheat

답변:


72

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

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

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

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

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

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

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


따라서 비트 필드가 1 인 행이 몇 개만있는 경우 (예 : "IsProcessed"추적) 인덱스가 값별로 정렬 된 다음 선택할 수 있기 때문에 좋은 것 같습니다. 아주 빨리 작은 작업 세트. 동의하는 경우 추가하면 동의합니다.
jeremcc

2
이전 의견에서 의미하는 바는 "비트 필드 (또는 좁은 범위)를 인덱싱 할 때 작업 집합을 절반으로 만 줄입니다."라는 문은 분포가 하나의 값에 크게 가중치를두면 사실이 아닙니다. 하지만 나머지 답변은 마음에 들기 때문에 수정하면 수락하겠습니다.
jeremcc

1
끝난. 백만 개의 행에 대해 비트 필드가 50 % 분포를 가질 것이라고 생각했지만 특정 문제 공간에 대해 작업 세트를 많이 줄일 수 있다는 것이 맞습니다.
Geoff Cox

인덱스가 있거나없는 실행 계획을 살펴보고 인덱스가 사용되고 있는지, 실제로 쿼리 비용을 줄이는 지 확인하는 것이 좋습니다. 쉽고 과학적입니다!
onupdatecascade 2010

비트 필드 + 다른 필드를 인덱싱하는 것은 어떻습니까? 예 : 웹 활동 로그에서 하나는 타임 스탬프를 인덱싱하지만 다른 유용한 인덱스는 모든 https 작업을 빠르게보기 위해 비트 필드 "IsHTTPS"+ 타임 스탬프에있을 수 있습니다. 그것도 비효율적일까요?
성분

19

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

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

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


1
쿼리의 조건자는 필터링 된 인덱스의 값으로 하드 코딩되어야합니다. 매개 변수에 값을 전달하면 yourBitColumn = @value최적화 프로그램이 필터링 된 인덱스를 사용할 수 있는지 여부를 확인할 수 없습니다.
geofftnz

2
이 문제를 해결할 방법이 있지만 당신 말이 맞습니다. 최적화 프로그램은 필터링 된 인덱스 조건에 일치하는 어떤 술어에 대한 값이이 작동하는 일반적인 계획을 생성하기 위해 최적화의 작업이기 때문에 정적 / 불변 것을 컴파일 타임에 보증이 필요 어떤 매개 변수를 설정합니다.
Ben Thul

9

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

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


8

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


2
행의 99 %가 비트 = 1이면 옵티마이 저는 인덱스를 무시하고 테이블 스캔을 수행해야합니다. 인덱스를 사용하는 것은 실제로 테이블 스캔보다 더 나쁠 것입니다. 적어도 회전 드라이브에서는 더 많은 I / O 및 디스크에서 비 연속 읽기가 가능합니다. 필터링 된 인덱스 (Postgres에 해당 : 부분 인덱스)를 사용하면됩니다. 나는 질문이 나온 지 몇 년이 지났기 때문에이 대답은 정당한 표를 얻지 못했습니다.
Andrew Lazarus

7

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

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


7
당신이 준 예에서, 나는 LastName을 먼저 넣는 경향이 있습니다. 특정 쿼리 워크로드에 따라 다르지만 일반적으로 더 선택적인 열을 먼저 사용하면 인덱스를 사용할 가능성이 더 높습니다.
Mitch Wheat

7

이 기사는 더 이상 표시되지 않습니다
Homer6

@ Homer6 나는이 기사의 새로운 집처럼 보이는 것에 대한 링크를 추가했다.
Jeff

새 링크는 Toad World 홈페이지로 이동합니다.
N West

Wayback 머신을 사용하여 기사를 찾았고 새로운 관련 기사를 찾았습니다. 도움이 되었기를 바랍니다.
Jeff

2

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

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


2

다른 사람들이 말했듯이 이것을 측정하고 싶을 것입니다. 이 글을 어디에서 읽었는지 기억 나지 않지만 인덱스가 효과적이려면 열의 카디널리티가 매우 높아야합니다 (약 95 %). 이에 대한 가장 좋은 테스트는 인덱스를 작성하고 BIT 필드의 0 및 1 값에 대한 실행 계획을 조사하는 것입니다. 실행 계획에 인덱스 검색 작업이 표시되면 인덱스가 사용된다는 것을 알 수 있습니다.

가장 좋은 방법은 기본 SELECT * FROM 테이블 WHERE BitField = 1을 사용하여 테스트하는 것입니다. 응용 프로그램에 대한 현실적인 쿼리가 나올 때까지 단계별로 기능을 천천히 구축하고 모든 단계에서 실행 계획을 검사하여 인덱스 검색이 여전히 사용되고 있는지 확인합니다. 물론이 실행 계획이 프로덕션에 사용될 것이라는 보장은 없지만 그럴 가능성이 높습니다.

일부 정보는 sql-server-performance.com 포럼 및 참조 문서 에서 찾을 수 있습니다.


중요한 것은 전체 열의 카디널리티가 아닙니다. WHERE 절의 선택성입니다. 따라서 값이 1 인 열이 거의없는 경우에도 인덱싱하는 것이 좋습니다. 50/50 (예 : 남성 / 여성)이면 그다지 가치가 없습니다.
WW.

2

"저는 카디널리티가 낮은 필드 (고유 값 수가 적음)를 인덱싱하는 것이 실제로 가치가 없다는 것을 읽은 적이 있습니다."

SQL Server는 거의 항상 인덱스를 읽는 것보다 테이블 스캔을 수행하는 것이 더 효율적이기 때문입니다. 따라서 기본적으로 인덱스는 사용되지 않으며 유지 관리하는 것은 낭비입니다. 다른 사람들이 말했듯이 복합 지수에서는 괜찮을 수 있습니다.


2

목표가 비트 필드 값이 '1'인 레코드를 더 빨리 쿼리하는 것이라면 비트 필드가 '1'인 레코드 만 포함하는 기본 테이블의 인덱싱 된 뷰를 시도 할 수 있습니다. Enterprise Edition에서는 쿼리가 쿼리 성능을 향상시키기 위해 지정된 테이블 대신 인덱싱 된 뷰를 사용할 수있는 경우 뷰를 사용합니다. 이론적으로 이것은 비트 필드 값이 '1'인 레코드 만 찾는 선택 쿼리의 속도를 증가시킵니다.

http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx

이 모든 것은 귀하가 Microsoft SQL Server 2005 Enterprise라고 가정합니다. 2008 년에도 동일하게 적용될 수 있습니다. 저는 그 버전에 익숙하지 않습니다.


2

인덱스에 원하는 효과가 있는지 알고 싶다면 : 다시 테스트하고 테스트하십시오.

일반적으로 인덱스를 유지하는 데 드는 비용 때문에 테이블을 충분히 좁히지 않는 인덱스는 원하지 않습니다. (비용> 이익). 그러나 귀하의 경우 색인이 표를 절반으로 줄이면 무언가를 얻을 수 있지만 표에 올려 놓을 수 있습니다. 그것은 모두 테이블의 정확한 크기 / 구조 및 사용 방법 (읽기 / 쓰기 수)에 따라 다릅니다.


1

그 자체로는 선택성이 거의 없기 때문에 아니오. 복합 색인의 일부로. 매우 가능하지만 다른 등식 열 이후에만 가능합니다.


1

당신은 할 수 없습니다 인덱스 SQL Server 2000에서 비트 필드, 당시 온라인에 표시되면서 :

비트

정수 데이터 유형 1, 0 또는 NULL.

비고

bit 유형의 열 은 인덱스를 가질 수 없습니다.

예, 수백만 개 중 소수의 행만있는 경우 색인이 도움이 될 것입니다. 하지만이 경우에 그렇게하려면 컬럼을tinyint .

참고 : Enterprise Manager에서는 비트 열에 인덱스를 만들 수 없습니다. 원하는 경우 비트 열에 수동으로 인덱스를 만들 수 있습니다.

CREATE INDEX IX_Users_IsActiveUsername ON Users
(
   IsActive,
   Username
)

그러나 SQL Server 2000은 실제로 이러한 인덱스를 사용하지 않습니다. 인덱스가 완벽한 후보가 될 쿼리를 실행합니다. 예를 들면 다음과 같습니다.

SELECT TOP 1 Username 
FROM Users
WHERE IsActive = 0

SQL Server 2000은 인덱스가 존재하지 않는 것처럼 대신 테이블 스캔을 수행합니다. 열을 tinyint SQL Server 2000으로 변경 하면 인덱스 검색 수행 . 또한 다음과 같은 다루지 않는 쿼리 :

SELECT TOP 1 * 
FROM Users
WHERE IsActive = 0

색인 검색을 수행 한 다음 책갈피 검색을 수행합니다.


SQL Server 2005는 비트 열의 인덱스를 제한적으로 지원합니다. 예를 들면 :

SELECT TOP 1 Username 
FROM Users
WHERE IsActive = 0

커버링 인덱스를 통해 인덱스 검색이 발생합니다. 그러나 보장되지 않는 경우 :

SELECT TOP 1 * 
FROM Users
WHERE IsActive = 0

인덱스 검색에 이어 책갈피 검색이 발생하지 않으며, 인덱스 검색을 수행 한 후 책갈피 검색을 수행하는 대신 테이블 스캔 (또는 클러스터 된 인덱스 스캔)을 수행합니다.

실험 및 직접 관찰에 의해 확인되었습니다.


참고로-SQL Server 2005 Management Studio에서는이를 수행 할 수 있습니다.
jeremcc

SQL Server 2000을 사용하여 비트 열에 인덱스를 설정할 수 있습니다.
Kibbee

내 SQL Server 2000 사본으로는 비트 열에 인덱스를 설정할 수 없습니다.
Ian Boyd

1

아주 늦은 대답 ...

예, SQL CAT 팀에 따라 유용 할 수 있습니다 (업데이트, 통합됨).


1
링크는 이제 죽은 것 같습니다. 그러나 해당 게시물은 전자 책 에 여러 다른 게시물과 함께 통합 된 것으로 보입니다 . 참조 된 섹션은 86 페이지에서 시작합니다. e-book은 "SQLCAT의 관계형 엔진 가이드"링크 아래 SQLCAT.com eBook 에서 다운로드 할 수 있습니다 .
mwolfe02 2014

0

이것은 일반적인 쿼리입니까? "소수"의 레코드를 찾을 때 그만한 가치가 있지만 다른 행에서는 그다지 도움이되지 않습니다. 데이터를 식별하는 다른 방법이 있습니까?


0

카디널리티는 하나의 요소이고 다른 하나는 인덱스가 데이터를 얼마나 잘 분할하는지입니다. 1과 0이 반 정도면 도움이 될 것입니다. (해당 인덱스가 다른 인덱스보다 더 나은 선택 경로라고 가정). 그러나 얼마나 자주 삽입하고 업데이트합니까? SELECT 성능을 위해 인덱스를 추가하면 INSERT, UPDATE 및 DELETE 성능도 저하되므로이를 염두에 두십시오.

1에서 0까지 (또는 그 반대로)가 75 %에서 25 %보다 낫지 않다면 신경 쓰지 마세요.


1
동의하지 않습니다. 배포가 50/50이면 테이블 스캔을 수행하는 것이 더 빠르기 때문에 인덱스를 사용하지 않습니다. 그러나 값이 5 개, 1 개, 0 개인 경우 1을 검색 할 때 인덱스를 사용할 가능성이 매우 높습니다.
Kibbee

0

전후 응답 시간을 측정 하고 가치가 있는지 확인하십시오. 이론적으로는 인덱싱 된 필드를 사용하는 쿼리의 성능을 향상시켜야하지만 실제로는 참 / 거짓 값의 분포와 관심있는 쿼리에 관련된 다른 필드에 따라 다릅니다.


0

Ian Boyd는 Enterprise Manager for SQL 2000을 통해이를 수행 할 수 없다고 말했을 때 정확합니다 (T-SQL을 통한 생성에 대한 그의 메모 참조).


0

쿼리하려면 여기에서 현명해야합니다. 시스템에서 true의로드가 더 많을 경우 열의로드 값을 알고 있어야하며 false가 아닌지 확인하기 위해 쿼리를 작성하는 모든 실제 값을 확인하려면 많은 도움이 될 것입니다. , 그것은 단지 속임수입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.