인덱스의 열 포함에 대한 강력하고 빠른 규칙


38

클러스터되지 않은 인덱스에 포함되는 열과 순서를 결정하는 강력하고 빠른 규칙이 있습니까? 방금이 게시물 https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index를 읽고 있었고 다음 쿼리에서 찾았습니다.

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

포스터는 다음과 같이 색인을 만들 것을 제안했습니다.

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

여기에 왜 우리가 이런 식으로 색인을 만들 수 없습니까?

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

또는

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

포스터가 LastName 열을 계속 포함하도록 결정하는 요인은 무엇입니까? 왜 다른 칼럼이 아닌가? 열을 유지해야하는 순서를 결정하는 방법은 무엇입니까?


3
INCLUDE에는 일반적으로 레코드를 찾은 후에 필요한 필드가 있어야하므로 더 많은 데이터를 얻기 위해 왕복 여행을 절약 할 수 있습니다. INCLUDE의 필드 순서는 중요하지 않습니다.
Jimbo

Ryk, 개인적으로이 게시물이 도움이된다고 생각합니다.
Jason Young

이 질문도 도움이됩니다. 개인을 스토킹하는 대신 좋은 질문과 좋은 답변에 집중합시다 ...
Volvox

답변:


47

marc_s의 색인 제안이 잘못되었습니다. 의견을 추가했습니다. (그리고 그것은 내 대답도 받아 들였다!)

이 쿼리의 인덱스는

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

색인은 일반적으로

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

어디:

  • KeyColList = 키 열 = 행 제한 및
    WHERE, JOIN, ORDER BY, GROUP BY 등 처리에 사용
  • NonKeyColList = 키가 아닌 열 = 선택 / 제한 후 SELECT 및 집계 (예 : SUM (col))에 사용

+1-OP의 샘플 색인이 쿼리에 가치가 없다는 데 동의합니다 (내 답변 참조).
JNK

큰! KeyColList 및 NonKeyColList의 순서를 결정하는 것은 한 가지 더 있습니다. 내 예를 들어 설명해 주시겠습니까? 내 쿼리가 SELECT EmployeeID, DepartmentID, LastName FROM EmployeeWHERE DepartmentID = 5, StateID = 4라고 가정 해 봅시다. 이제 인덱스는 어떻게 되나요?

@Rocky- NonKeyColList순서는 중요하지 않습니다. KeyColList순서는 쿼리에 사용될 것으로 예상되는 순서대로 정렬되어야합니다. 아래 답변에 대한 메모를 참조하십시오 Last Name, First Name, Middile Initial. 전화 번호부 와 같습니다 . 두 번째 필드를 찾으려면 첫 번째 필드가 필요합니다.
JNK

@gbn 포함 목록에 실제로 EmployeeID가 필요합니까? EmployeeID 열에 클러스터형 인덱스가 있고 그 위에 DeptId 열에 비 클러스터형 인덱스를 만들면 비 클러스터형 인덱스에 이미 INCLUDE 목록의 클러스터링 키를 포함하여 비 클러스터형 인덱스 구조에 포함 된 클러스터링 키에 대한 참조가 있습니다 ' 어떤 혜택도 추가하지 마십시오.
Viswanathan Iyer

1
@ViswanathanIyer 실제 온 디스크 스토리지에 두 번 추가되지는 않습니다. SQL Server가이를 감지합니다. 따라서 필요하지는 않지만 더 명확합니다. 그러나 우리는 질문에 클러스터 된 인덱스를 알지 못하므로 아무 것도 가정하지 않는 것이 안전합니다.
gbn

19

JNK와 gbn은 큰 대답을했지만 단일 쿼리에만 초점을 두는 것이 아니라 큰 그림을 고려해 볼 가치가 있습니다. 이 특정 쿼리는 인덱스 (# 1)의 이점을 얻을 수 있지만 :

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

다음과 같이 쿼리가 약간 변경되면이 인덱스가 전혀 도움이되지 않습니다.

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

인덱스 (# 2)가 필요합니다.

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

부서 5에 1,000 명의 직원이 있다고 가정하십시오. 인덱스 # 1을 사용하여 모든 스미스를 찾으려면 포함 된 열이 키의 일부가 아니므로 부서 5의 1,000 개 행을 모두 검색해야합니다. 인덱스 # 2를 사용하면 LastName Smith 부서 5를 직접 찾을 수 있습니다.

따라서 인덱스 # 2는 더 넓은 범위의 쿼리를 처리하는 데 더 유용하지만 비용은 부풀려진 인덱스 키이므로 인덱스의 비 리프 페이지가 더 커집니다. 모든 시스템이 다르므로 여기에는 규칙이 없습니다.


참고로, EmployeeID가이 테이블의 클러스터링 키인 경우 (클러스터형 인덱스를 가정 할 경우) EmployeeID를 포함 할 필요가 없습니다. 모든 비 클러스터형 인덱스에 존재하므로 인덱스 # 2는 있다,이다

Employee(DepartmentID, LastName)

2
더 유용한 정보는 +1입니다. 마지막으로, 나는 이것을 테스트했으며 EmployeeID가 클러스터형 인덱스이면 INCLUDE에서 EmployeeID의 명시 적 사용은 실제로 무시됩니다 (색인의 크기에 따라). 내가 생각하지만 공간 단점이 없다는 것이 더 분명합니다.
gbn

1
나는 절대적으로 동의합니다-특히 비용이 들지 않으면 항상 명시 적으로하는 것이 좋습니다!

1
만약을 대비해서 ... INCLUDE (클래식 EmployeeID 아님)에서 클러스터 된 키를 테스트했으며 공간이 추가되지 않았다는 의미입니다. 주요 열에서 그렇게합니다.
gbn

@gbn 예, 클러스터 키는 INCLUDE 열이있는 인덱스의 리프 수준에만 있어야합니다. 인덱스 키로 이동하면 리프가 아닌 페이지에도 존재합니다. 이로 인해 약간의 부풀어 오름이 발생하지만 끔찍한 양은 아닙니다 (중간 레벨 페이지에서는 정수를 가정 할 때 리프 레벨 페이지 당 다른 4 바이트를 추가합니다).

sqlperformance.com/2014/07/sql-indexes/… 이 기사에 설명 된 일부 효과를 포함하는 훌륭한 답변입니다. 쿼리가 변경되면 인덱스 요구 사항도 변경하십시오. Jim의 답변으로 더 나을 수도 있지만 @gbn 답변으로 더 나아질 수 있습니다.
John aka hot2use

7

나는 당신이 첫 번째 것을 어떻게 얻었는지 잘 모르겠습니다. 나에게 그 쿼리에는 다음을 사용합니다.

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

SQL에는 거의 아무것도 "빠르고 빠른 규칙"이 없습니다.

그러나 예를 들어, 색인에서 사용할 유일한 필드 DepartmentIDWHERE절 에 있기 때문 입니다.

다른 필드는 쉽게 접근 할 수 있어야합니다. DepartmentID다음을 기준으로 선택 INCLUDE하면 색인의 리프 노드에 해당 필드가 있습니다.

다른 인덱스는이 인덱스에서 작동하지 않으므로 다른 예제를 사용하고 싶지 않습니다.

전화 번호부와 같은 색인을 생각하십시오. 대부분의 전화 번호부는 성, 이름, 중간 이름으로 주문됩니다. 누군가의 이름은 알고 있지만 성은 모르면 전화 번호부 색인 순서에 따라 이름을 검색 할 수 없으므로 전화 번호부는 좋지 않습니다.

INCLUDE필드는이 책의 각 항목에 대한 전화 등 번호, 주소, 기타 정보 같다.

편집하다:

사용하지 않는 이유를 더 명확하게 설명하려면 다음을 수행하십시오.

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

이 인덱스는 EmployeeID또는 둘 다 EmployeeID 있고 절 LastName에 있는 경우에만 유용합니다 WHERE. 이 꽤 많이있다 OPPOSITE 이 쿼리에 필요한 무엇.


@ajbeaven은 사실이므로 편집에 언급 한 의견에 EITHER employeeID 또는 두 열이 필요하다고 말합니다.
JNK

durr 죄송합니다 오해 :(
ajbeaven

0

그래도 여전히 (employee_id, department_id) 색인을 사용할 수 있다고 생각하지만 where 구문에 '더미'줄을 포함시켜야합니다. "employee_id = employee_id)

  • 인덱스 (employee_id, departemnent_id)가있는 경우
  • department_id에서만 검색 / 제한해야 함
  • 잘못된 순서로 인해 인덱스를 사용하지 않는다는 것을 알고 있습니다 (또는 지금까지 상황이 바뀌었고 다음 "트릭"이 더 이상 필요하지 않습니다. 나는 "oldy"입니까?) .
  • "오래된"tricK를 사용하십니까?

    emp.employee_id = emp.employee_id 및 emp.department_id = 5 인 Employee emp
    에서 *를 선택하십시오.

(그래서 여기서 성의 포함 부분에 중점을 두지 않고 예 또는 키를 사용하지 않는 것에 중점을 둡니다.)

친절하다,

미겔


2
아니요, 쓸모없고 비효율적입니다.
ypercubeᵀᴹ

특히, 모든 직원 ID를 검색하여 department_id 5의 모든 인스턴스를 찾으려면 인덱스 스캔이 필요합니다. 직원 수가 1000 명이고 부서가 5 명인 경우 SQL은 1000 명을 모두 조사하여 특정 부서의 모든 행을 찾아야합니다.
마크 수울

이제 반대의 경우를 고려하십시오 (색인은 department_id, employee_id에 있습니다). 분명히 특정 부서를 쉽게 찾을 수 있지만 특정 직원을 찾으려면 SQL은 5 개 부서 만 스캔하여 특정 직원의 모든 행을 찾아야합니다.
마크 수울
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.