programing

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

jooyons 2023. 4. 15. 08:44
반응형

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

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

1억 행의 테이블이 있고 비트 필드가 1인 레코드를 선택하면 어떻게 됩니까?어느 시점에서도 비트필드가 1인 레코드는 몇 개밖에 없다고 합시다(0이 아닙니다).비트 필드를 인덱싱할 가치가 있나요, 아닌가요? 왜요?

물론 시험해보고 실행계획을 확인하면 됩니다만, 그 이면에 있는 이론도 궁금합니다.카디널리티가 중요한 시기와 중요하지 않은 시점은 언제입니까?

SQL에 인덱스가 있는 경우를 생각해 보십시오. 인덱스는 실제로 메모리의 다른 청크를 가리키는 메모리 청크(행 포인터)입니다.인덱스는 사용량에 따라 인덱스의 일부를 메모리에서 로드 및 언로드할 수 있도록 페이지로 분할됩니다.

행 집합을 요청하면 SQL은 인덱스를 사용하여 테이블 검색보다 빠르게 행을 찾습니다(모든 행을 참조).

SQL에 클러스터된 인덱스와 비클러스터된 인덱스가 있습니다.클러스터된 인덱스에 대한 저의 이해는 비슷한 인덱스 값을 같은 페이지로 그룹화한다는 것입니다.이 방법으로 인덱스 값과 일치하는 모든 행을 요청하면 SQL은 메모리의 클러스터된 페이지에서 해당 행을 반환할 수 있습니다.그렇기 때문에 GUID 열을 클러스터화하려고 하면 안 됩니다. 랜덤 값을 클러스터화하려고 하지 않습니다.

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

따라서 SQL은 반복해야 하는 작업 세트(행 수)를 줄이려고 합니다.

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

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

나는 다른 방법으로 이 문제를 우연히 발견했다.소수의 레코드만 1의 값을 가정한다고 가정할 때(관심 있는 레코드가 해당) 필터링된 인덱스를 선택하는 것이 좋습니다.예를 들어 다음과 같습니다.

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

그러면 최적기가 쿼리의 술어일 때 사용할 수 있을 만큼 스마트한 인덱스가 상당히 작아집니다.

비트 필드가 1로 설정된 몇 개만 있는 1억 개의 레코드?네, 비트 필드를 인덱싱하면 비트=1 레코드에 대한 쿼리가 확실히 빨라질 것입니다.인덱스에서 로그 검색 시간을 얻은 다음 bit=1 레코드가 있는 몇 페이지만 터치해야 합니다.그렇지 않으면 1억 장의 기록표를 전부 만져야 할 거야

한편, 저는 데이터베이스 전문가가 아니기 때문에 중요한 것을 놓치고 있을 가능성이 있습니다.

99% 행이 비트 = 1이고 1%가 비트 = 0인 것과 같이 분포가 상당히 알려져 있고 불균형한 경우 비트 = 1인 WHERE 절을 실행하면 전체 테이블 스캔이 인덱스 스캔과 거의 비슷한 시간이 됩니다.빠른 쿼리를 bit = 0으로 설정하려면 WHERE 비트 = 0 절을 추가하여 필터링된 인덱스를 생성하는 것이 가장 좋습니다.이렇게 하면 인덱스는 1% 행만 저장합니다.그런 다음 WHERE 비트 = 0을 실행하면 쿼리 옵티마이저가 해당 인덱스를 선택할 수 있으며, 여기서 나오는 모든 행은 비트 = 0이 됩니다.또한 비트의 전체 인덱스에 비해 필요한 Disk 공간이 매우 적다는 이점도 있습니다.

비트열만 인덱스를 만들지는 않지만 복합 인덱스의 일부로 비트열을 포함하는 것은 매우 일반적입니다.

단순한 예로는 이름뿐만 아니라 활성(ACTIVE)의 색인(LASTNAME)을 들 수 있습니다.이 예에서는 어플리케이션이 거의 항상 액티브한 고객을 찾고 있습니다.

물론, 특히 그 값으로 데이터를 검색해야 하는 경우에는 그럴 가치가 있습니다.이는 정규 행렬 대신 희박 행렬을 사용하는 것과 유사합니다.

SQL 2008에서는 파티션 기능을 사용할 수 있으며 인덱스에 포함된 데이터를 필터링할 수 있습니다.이전 버전의 단점은 인덱스가 모든 데이터에 대해 작성된다는 것이지만 대상 값을 별도의 파일 그룹에 저장하여 최적화할 수 있다는 것입니다.

다른 사람들이 말한 것처럼, 당신은 이것을 측정해야 할 것입니다.어디서 읽었는지 기억나지 않지만 인덱스를 유효하게 하려면 열의 카디널리티가 매우 높아야 합니다(약 95%).이를 위한 최선의 테스트는 인덱스를 작성하고 BIT 필드의 0 및 1 값에 대한 실행 계획을 조사하는 것입니다.실행 계획에 인덱스 검색 작업이 있는 경우 인덱스가 사용됨을 알 수 있습니다.

가장 좋은 방법은 기본 SELECT * FROM 테이블 WHERE BitField = 1을 사용하여 를 테스트하는 것입니다.여기서부터 어플리케이션에 대한 현실적인 쿼리를 얻을 때까지 단계적으로 기능을 구축하고 실행 계획을 모든 단계에서 검토하여 인덱스 탐색이 여전히 사용되고 있는지 확인하는 것입니다.물론 이 실행계획이 생산에 사용될 것이라는 보장은 없지만 그럴 가능성은 충분히 있다.

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

"한 번은 카디널리티가 낮은 필드(별도의 값 수가 적은 필드)를 인덱싱할 가치가 없다는 것을 읽은 적이 있습니다."

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

비트 필드 값이 '1'인 레코드에 대한 쿼리를 빠르게 하는 것이 목표인 경우 비트 필드가 '1'인 레코드만 포함하는 기본 테이블의 인덱스 보기를 시도할 수 있습니다.엔터프라이즈 에디션에서 쿼리가 지정된 테이블 대신 인덱스된 뷰를 사용하여 쿼리 성능을 향상시킬 수 있는 경우 뷰를 사용합니다.이론적으로는 비트 필드 값이 '1'인 레코드만 검색하는 선택 쿼리의 속도가 빨라집니다.

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

이 모든 것은 사용자가 Microsoft SQL Server 2005 Enterprise라고 가정합니다.2008년에도 마찬가지일 수 있습니다.저는 그 버전을 잘 모릅니다.

인덱스가 원하는 효과를 가지는지 여부를 확인하려면: 테스트하고 다시 테스트합니다.

일반적으로 인덱스를 유지하는 비용(비용 > 이익) 때문에 테이블을 충분히 좁히지 않는 인덱스는 원하지 않습니다.그러나 당신의 경우 인덱스가 테이블을 반으로 자른다면 테이블 위에 올려놓는 것 외에 얻을 수 있는 것이 있을지도 모릅니다.이 모든 것은 테이블의 정확한 크기/구조와 사용방법(읽기/쓰기 수)에 따라 달라집니다.

그 자체로는 선택성이 거의 없기 때문에 없습니다.복합 인덱스의 일부로서.가능성이 높지만 다른 등식열 뒤에만 해당됩니다.

당시 Books Online에 표시된 바와 같이 SQL Server 2000에서는 비트필드를 인덱싱할 수 없습니다.

조금

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

언급

형식 비트 열에는 인덱스를 포함할 수 없습니다.

줄 에서 몇 이 됩니다. 이럴 때 이 을 a로 요.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은 테이블스캔을 수행하여 인덱스가 존재하지 않는 것처럼 동작합니다.열을 작은 크기로 변경하면 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 CAT 팀에 따라 도움이 될 수 있습니다(업데이트 완료, 통합 완료).

이게 일반적인 질문인가요?레코드의 "핸들리"를 찾을 때 가치가 있을 수 있지만 다른 행에서는 별로 도움이 되지 않습니다.데이터를 식별할 수 있는 다른 방법이 있습니까?

카디널리티는 한 가지 요인이고, 다른 요인은 인덱스가 데이터를 얼마나 잘 분할하느냐입니다.1/2과 0의 반 정도가 있으면 도움이 됩니다(다른 인덱스보다 인덱스를 선택하는 것이 좋다고 가정합니다).단, 삽입 및 업데이트 빈도는 어떻게 됩니까?SELECT 성능의 인덱스를 추가하면 INSERT, UPDATE 및 DELETE 성능도 저하되므로 유의하십시오.

1에서 0까지(또는 그 반대)가 75%에서 25%보다 낫지 않다면 신경 쓰지 않아도 됩니다.

응답 시간을 전후로 측정하여 가치가 있는지 확인합니다.이론적으로는 인덱스된 필드를 사용하여 쿼리의 성능을 향상시킬 수 있지만 실제로는 참/거짓 값 및 관심 있는 쿼리와 관련된 다른 필드의 분포에 따라 달라집니다.

Ian Boyd가 Enterprise Manager for SQL 2000을 사용할 수 없다고 말한 것은 옳습니다(T-SQL을 통한 작성에 대한 메모 참조).

쿼리하려면 여기서 스마트해야 합니다.시스템에 true의 부하가 더 큰 경우 컬럼의 부하값을 알아야 합니다.또, false가 아닌 것을 체크하기 위해서 쿼리에 기입되어 있는 모든 true 값을 체크해야 합니다.많은 도움이 될 거야, 그냥 속임수일 뿐이야

언급URL : https://stackoverflow.com/questions/231125/should-i-index-a-bit-field-in-sql-server

반응형