데이터베이스 인덱스를 따르는 모범 사례 [닫기]


17

인덱스를 사용하여 데이터베이스 성능을 개선하기위한 일부 DO 및 DONT는 무엇입니까?

DO는 인덱스를 만들어야하는 경우이거나 성능을 향상시키는 다른 인덱스 관련 팁입니다.

DONT는 인덱스를 작성하지 않아야하는 경우 또는 성능을 저하시킬 수있는 다른 인덱스 관련 조치입니다.


3
프로필, 프로필, 프로필
GrandmasterB

답변:


15

이는 일반적으로 인덱스가 삽입 및 업데이트 속도를 늦추고 쿼리 속도를 높이기 때문에 데이터베이스의 용도에 부분적으로 의존합니다. 데이터웨어 하우스에는 일반적으로 업데이트 및 일괄 삽입이 없으므로 인덱스 및 많은 쿼리를 쉽게 생성 할 수 있으므로 인덱스가 많이 생성됩니다. 웹 판매 등을위한 온라인 데이터베이스에는 많은 인서트 및 업데이트가 있으므로 신중하게 선택한 인덱스가 몇 개 이상이면 속도가 느려집니다.

특정 유형의 쿼리가 많이있는 경우 쿼리에 대한 인덱스를 만들 수 있지만 데이터웨어 하우스보다 온라인 처리에 더 적합합니다. 특정 열이 쿼리에서 많이 나오는 경우 해당 열에 대한 인덱스를 원할 수 있으며 이는 데이터웨어 하우스에 특히 유용합니다. 데이터웨어 하우스에는 여러 가지 다른 예측할 수없는 방식으로 쿼리됩니다.

인덱스를 추가하거나 제거 할 때마다 성능 테스트를 수행하여 그 효과를 확인하십시오. 그것 없이는, 당신은 장님을 쏘고 있습니다.

쿼리 및 데이터베이스 조정에 대한 서적이 있으며, 종종 하나의 데이터베이스 시스템과 해당 RDBMS 도구 사용에 관한 책이 있습니다. 그러나 데이터베이스를 많이 최적화해야하는 경우 대규모 작업을 수행하고 있으며 적절한 전문 지식을 갖춘 DBA를 고용해야합니다.


17

테이블 사용 방법에 따라 크게 다릅니다. 하나의 간단한 대답은 없습니다.

나는 당신을 줄 수있는 최고의 조언은 : 사용 튜닝 고문 . 응용 프로그램을 사용하는 동안 데이터베이스 명령을 분석 한 다음 이에 대한로드 테스트를 수행하여 의미있는 조언을 제공합니다.

그것들은 SQL ServerOracle을 위해 존재합니다 . 다른 DBMS에 그러한 DBMS가 있는지는 모르겠지만 그러한 기본 도구를 제공하지 않는 것 같습니다.

몇 가지 무작위 명령 :

  • 인덱스는 종종 WHERE 절에 포함 된 열에 적용될 때 고성능을 제공합니다
  • 쿼리에서 가장 많이 사용 된 열에 클러스터형 인덱스를 사용하십시오.
  • 열 조합으로 여러 색인을 작성할 수 있음을 잊지 마십시오 (쿼리에 사용됨)
  • 인덱스가 많으면 INSERT 명령의 성능이 저하됩니다.

마지막 조언 : DB 퍼포먼스가 프로젝트에 정말로 중요한 경우 전문가를 고용하십시오. 내가 한 일이야


2
열 조합에 대한 인덱스의 경우 +1입니다. 컬럼의 인덱스 ab하지 의 인덱스와 동일 (a, b). 후자는 거의에 인덱스 좋은 같습니다 a에 조건 쿼리를 가속화하기위한 a,에 대량 더 나은 조건 쿼리입니다 ab및 조회에 유용하지 않습니다 b만. (대부분의 데이터베이스는 사용하지 않습니다. 오라클은 정기적으로 수행하는 마일리지를 얻지 못합니다.)
btilly

2
+1, "쿼리 계획을 읽는 법을 배워서 무엇을 인덱싱할지 알 것"
Steven A. Lowe

4

@Pierre 303은 이미 그것을 말했지만 다시 말할 것입니다. DO는 열 조합에 인덱스를 사용합니다. 결합 된 인덱스 (a, b)는 단독 a인덱스보다 쿼리의 경우 속도가 약간 느리고 쿼리 a가 두 열을 결합하면 훨씬 좋습니다. 일부 데이터베이스에 인덱스를 가입 할 수 있습니다 ab테이블을 타격하기 전에,하지만이 결합 된 인덱스를 가진 것으로 잘 거의 없습니다. 결합 된 인덱스를 만들 때 가장 많이 검색 될 가능성이 높은 열을 결합 된 인덱스에 배치해야합니다.

데이터베이스가 지원하는 경우, DO는 쿼리보다는 열에 표시 기능에 인덱스를 넣습니다. (열에서 함수를 호출하는 경우 해당 열의 인덱스는 쓸모가 없습니다.)

당신은 당신이 (예를 들어, PostgreSQL을, MySQL은,하지만, 만들고 즉시 파괴 할 수 있다는 사실 임시 테이블과 데이터베이스를 사용하는 경우 하지 오라클), 다음 마십시오 임시 테이블에 인덱스를 만들 수 있습니다.

당신이 그것을 할 수있는 데이터베이스 (예 : 오라클)를 사용하는 경우, DO의 좋은 쿼리 계획 잠금. 시간이 지남에 따라 쿼리 최적화 프로그램은 쿼리 계획을 변경합니다. 그들은 보통 계획을 개선합니다. 그러나 때때로 그들은 극적으로 악화시킵니다. 일반적으로 계획 개선은 눈치 채지 못할 것입니다. 쿼리에는 병목 현상이 없었습니다. 그러나 하나의 나쁜 계획은 바쁜 사이트를 중단시킬 수 있습니다.

큰 데이터로드를 수행하려는 테이블에는 인덱스가 없습니다 . 테이블을로드 할 때 인덱스를 유지 관리하는 것보다 인덱스를 삭제하고 데이터를로드 한 다음 인덱스를 다시 작성하는 것이 훨씬 빠릅니다.

큰 테이블의 작은 부분 이상에 액세스해야하는 쿼리에는 인덱스를 사용 하지 마십시오 . 예를 들어 이름과 성별이있는 데이터가있는 경우 이름이 전체 행의 작은 부분을 나타 내기 때문에 이름을 인덱싱 할 수 있습니다. 여전히 행의 50 %에 액세스해야하므로 성별을 색인하는 것은 도움이되지 않습니다. 대신 전체 테이블 스캔을 사용하려고합니다. 그 이유는 인덱스가 큰 파일에 무작위로 액세스하여 디스크 검색이 필요하기 때문입니다. 디스크 탐색 속도가 느립니다. 예를 들어 최근에 다음과 같은 쿼리 시간을 1 시간 단축했습니다.

SELECT small_table.id, SUM(big_table.some_value)
FROM small_table
  JOIN big_table
    ON big_table.small_table_id = small_table.id
GROUP BY small_table.id

다음과 같이 다시 작성하여 3 분 미만으로

SELECT small_table.id, big_table_summary.summed_value
FROM small_table
  JOIN (
      SELECT small_table_id, SUM(some_value) as summed_value
      FROM big_table
      GROUP BY small_table_id
    ) big_table_summary
    ON big_table_summary.small_table_id =  small_table.id

이로 인해 데이터베이스는에 유혹 색인을 사용해서는 안된다는 것을 이해하도록 강요했습니다 big_table.small_table_id. (Oracle과 같은 우수한 데이터베이스는 자체적으로 파악해야합니다.이 쿼리는 MySQL에서 실행되고있었습니다.)

업데이트 : 여기 내가 만든 디스크 탐색 지점에 대한 설명이 있습니다. 인덱스는 데이터가 테이블의 어디에 있는지 빠르게 검색합니다. 보아야 할 데이터 만 볼 수 있기 때문에 이것은 일반적으로 승리입니다. 그러나 특히 많은 데이터를 최종적으로 살펴 보는 경우에는 항상 그런 것은 아닙니다. 디스크는 데이터를 잘 스트리밍하지만 조회 속도가 느려집니다. 디스크의 데이터를 무작위로 조회하는 데 1/200 초가 걸립니다. 쿼리의 느린 버전은 600,000의 작업과 같은 작업을 수행하여 약 1 시간이 걸렸습니다. 빠른 검색 버전은 70MB / 초와 같은 속도로 모든 것을 읽고 데이터를 스트리밍해야한다는 것을 알았습니다. 3 분 안에 11GB 테이블을 통과했습니다.


안녕하세요, 당신의 모범에 혼란 스럽습니다. 인덱스를 사용하면 작업 속도가 빨라질 것이라고 생각했을 것입니다. 쿼리가 테이블의> 5 %에 ​​액세스하는 경우 검색중인 열에 인덱스를두면 속도가 느려질 것입니까?
Upvote를 클릭하십시오

@Click Upvote : 쿼리가 테이블의 5 % 이상 (하드웨어 및 데이터에 크게 좌우 됨)에 액세스하면 해당 쿼리에 인덱스를 사용하지 않는 것이 더 빠릅니다. 인덱스를 사용하더라도 인덱스를 사용하지 않는 한 아프지 않습니다. 그 이유에 대해 더 자세히 업데이트하겠습니다.
btilly

유용한 정보. 예를 들어 mysqlperformanceblog.com/2007/08/28/…에 대한 자세한 내용은 ... 그러나 '키를 무시'하여 하위 쿼리로 만들어야하는 것은 아닙니다.
잉카

@ 잉카 : 나는 '무시 키'를 알지 못했습니다. 내가 모르는 데이터베이스 관련 사항이있을 정도로 데이터베이스를 충분히 전환합니다. 그것의 소리에서 작동하지만 내 최종 솔루션보다 훨씬 덜 효율적입니다. 차이점은 그 그룹이 참여한 다음 그룹화 한 다음 그룹화 한 다음 참여한다는 점입니다. 적은 수의 레코드를 조인해야하므로 조인 작업이 줄어 듭니다.
btilly

"좋은 데이터베이스 (예 : Oracle이지만 MySQL은 아님)": 특히 MySQL이 여러 인덱스를 동시에 완벽하게 사용할 수 있다는 사실을 무시할 때 (예 : 쿼리 계획에서 "INDEX MERGE"로 표시) 어리석은 판촉물을 피하십시오. .
Patrick Allaert

2

DO : 쿼리 및 / 또는 비교를 통해 가장 많이 액세스하는 필드를 인덱싱하십시오.

DO N'T : 테이블의 모든 필드를 색인화하여 더 빠르게 만들 것이라고 생각하십시오.

통계가 없지만 테이블에 색인 필드를 4 개 이하로 유지하려고 노력합니다. 데이터베이스를 정규화하면 숫자 키로 모든 것을 검색 할 수 있기 때문에 일반적으로 이러한 숫자를 유지하는 데 도움이됩니다 (어쨌든 더 빠름). 인덱싱을 위해 전체 텍스트 필드를 멀리하려고합니다. 그들은 꽤 무겁습니다.


2

기본적으로 인덱스는 검색 속도를 높이지만 쓰기 속도는 느려지 며 공간을 차지합니다. 그것은 절충안입니다.

결합, 검색 / 비교 또는 정렬에 자주 사용되는 필드는 색인의 후보입니다. 그것이 정말로 유익하다는 것을 알기 위해서는 측정하십시오. 그러나 많은 (> 1000s)의 레코드와 적은 수의 삽입이있는 과도하게 조인 된 테이블의 외래 키는 지불 할 것입니다.

텍스트 필드의 경우 쿼리의 속도를 높이지만 인덱스의로드를 가볍게하는 필드의 일부 (예 : 처음 6 자)를 인덱스 할 수 있습니다. 전체 텍스트 검색 (에 대한 검색 like %substring%)에는 익숙하지 않은 다른 기술이 필요하므로 조언을 드릴 수 없습니다.

인덱스가 도움이되지 않는 중요한 상황 : 날짜의 일부를 검색 (/ 가입 / 주문) 할 때 전체 날짜 또는 날짜 / 시간 필드 색인을 사용할 수 없습니다. 에 대한 색인 date_created은와 같은 검색어를 사용하는 데 도움이되지 않습니다 select * from t where year(date_created) = 2011. mysql에서는 날짜의 일부에 색인을 만들 수 없습니다. ( ' between' 를 사용 하지 않고 year()날짜 필드의 색인을 사용할 수 있습니다.)

매뉴얼의 MYSQL에 대한 자세한 정보 : http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html


1

DO : 클러스터 된 인덱스의 총 크기를 최소로 유지하십시오. 클러스터 된 인덱스 항목은 다른 비 클러스터형 인덱스에 포함되며 여기에서 디스크 공간을 낭비 할 가능성이 있습니다.


1

표는 어휘집으로, 기사는 모양 순서대로 (또는 전혀 도움이되지 않는 순서로) 정렬되며, 테이블 색인은 해당 어휘집에 대한 책 색인으로 생각하십시오.

색인을 사용하여 책에서 무언가를 빨리 찾습니다. 책 전체를 스캔하는 대신 인덱스에서 키 (일반적으로 카테고리, 과학 분야, 역사적 시대 등)를 정렬하기 만하면 스캔 할 필요가 없습니다. 전체 색인)으로 이동 한 다음 오른쪽 페이지로 이동하십시오.

그러나 책과 달리, 표는 한 번 인쇄 된 다음에 변경할 수 없습니다. 항상 업데이트되므로 모든 인덱스를 업데이트해야합니다. 이것은 물론 공간 및 시간 비용으로 이루어지며 인덱스의 유용성에 의해서만 정당화 될 수 있습니다.

따라서 해당 열이 빈번한 검색어의 키로 사용되는 경우 열에 대한 색인을 사용하고 그렇지 않은 경우 사용하지 마십시오. 잦은 단어 는 일반적으로 말할 때 얻을 수있는만큼 정량화됩니다. 결국 어느 것이 빈번한 지 잘 추정 한 다음 의심스러운 경우 인덱스가 있거나없는 성능을 간단히 벤치마킹해야합니다.

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