인덱스 : 노드 수가 동일한 경우 정수 대 문자열 성능


26

PostgreSQL (9.4) 데이터베이스를 사용하여 Ruby on Rails에서 응용 프로그램을 개발 중입니다. 내 유스 케이스의 경우 응용 프로그램의 전체 지점이 모델에서 매우 특정한 속성을 검색하므로 테이블의 열이 매우 자주 조회됩니다.

내가 현재 사용할지 여부를 결정하고 integer(예를 들어, 일반적인 스트링 타입 사용 단순히 유형을하거나 character varying(255), 레일의 기본이다 나는 확실히 성능 차이가 인덱스에 일 무슨 아니에요 같이 컬럼을).

이 열은 열거 형 입니다. 가능한 값의 크기는 고정 된 크기입니다. 대부분의 열거 길이는 5를 초과하지 않으므로 응용 프로그램 수명 동안 인덱스가 다소 고정됩니다 . 따라서 정수 및 문자열 인덱스는 노드 수에서 동일합니다.

그러나 인덱싱되는 문자열은 길이가 약 20 자일 수 있으며 메모리에서 정수의 약 5 배입니다 (정수가 4 바이트이고 문자열이 문자 당 1 바이트의 순수 ASCII 인 경우 유지됩니다). 데이터베이스 엔진이 인덱스 조회를 수행하는 방법을 모르지만 정확히 일치 할 때까지 문자열을 "스캔"해야하는 경우 본질적으로 문자열 조회가 정수 조회보다 5 배 느리다는 것을 의미합니다. 정수 조회와 일치 할 때까지 "스캔"은 20 대신 4 바이트입니다. 이것은 내가 상상하는 것입니다.

조회 값은 (정수) 4 :

스캐닝 ............................ FOUND | 레코드를 가져 오는 중 ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... ||

조회 값은 (문자열) "some_val"(8 바이트)입니다.

스캐닝................................................. .................................... FOUND | 레코드를 가져 오는 중 ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... ||

나는 그것이 의미가 있기를 바랍니다. 기본적으로 정수는 적은 공간을 차지하기 때문에 문자열보다 "일치"할 수 있습니다. 아마도 이것은 완전히 잘못된 추측 일 것입니다. 그러나 나는 전문가가 아니므로 여러분에게 묻는 이유입니다! 나는 그 생각 난 그냥 발견이 대답은 내 가설을지지하는 것 같다,하지만 확실하게합니다.

열에서 가능한 값의 수는 둘 중 하나를 사용하여 변경되지 않으므로 인덱스 자체가 변경되지 않습니다 (열거에 새로운 값을 추가하지 않은 경우). 이 경우 integeror 사용시 성능 차이가 있거나 varchar(255)정수 유형을 사용하는 것이 더 의미가 있습니까?


내가 묻는 이유는 Rails enum유형이 정수를 문자열 키에 매핑하지만 사용자가 열을 의미하는 것은 아닙니다. 기본적으로 유효하지 않은 값으로 인해 ArgumentError유효성 검사가 실행되기 전에 열거 형 값이 유효한지 확인할 수 없습니다. 사용 string유형은 검증을 허용,하지만 성능 비용이 있다면 차라리 그냥 확인 문제를 해결 떨어져 해킹 것입니다.

답변:


32

짧은 대답 : 모든면에서 또는 모든면에서 integer빠릅니다 . 작은 테이블 및 / 또는 짧은 키에는별로 중요하지 않습니다. 키 길이와 행 수에 따라 차이가 커집니다.varchartext

string ... 20 자 길이로 메모리에서 정수의 약 5 배입니다 (정수가 4 바이트이고 문자열이 문자 당 1 바이트의 순수 ASCII 인 경우 유지됨)

정확하게 말하면 문자 유형 ( text또는 varchar)은 디스크의 ASCII 문자 20 개와 RAM의 23 바이트에 대해 정확히 21 바이트를 차지합니다 . 자세한 평가 :

또한 중요 : COLLATION규칙은 숫자 데이터 유형과 달리 문자 데이터 정렬을 더 비싸게 만들 수 있습니다.

인덱스 크기 는 대부분의 경우 성능 차이의 큰 부분을 차지할 것입니다. 인덱스 튜플 당 오버 헤드 (기본적으로 테이블의 경우와 동일)를 고려하십시오 . 항목 포인터의 경우 4 바이트 , 튜플 헤더의 경우 24 바이트 입니다. 그래서에 대한 인덱스 튜플 integer에 달할 것이라고 36 바이트 (4 바이트를 포함하여 정렬 패딩 )과 위해 varchar(20)가 될 20 개 ASCII 문자로 52 바이트 (또한 포함. 패딩). 세부:

모든 이론은 제쳐두고 : 테스트하는 것이 가장 좋습니다 :

Postgres 9.5 는 긴 문자열의 문자열을 정렬하기위한 최적화 기능을 도입했습니다 (키워드 "축약 된 키" ). 그러나 Linux에서 일부 C 라이브러리 함수의 버그로 인해 프로젝트에서 Postgres 9.5.2의 비 C 데이터 정렬 기능을 비활성화했습니다. 릴리스 정보의 세부 사항

그러나 실제로 Postgres enum유형을 사용하는 경우 이러한 고려 사항의 대부분은 integer내부적 으로 값 으로 구현되므로 관련이 없습니다 . 매뉴얼 :

enum값은 디스크에 4 바이트를 차지합니다.

제쳐두고 : varchar(255)초기 버전의 SQL Server에서는 의미가 있으며 내부적으로 최대 255 자까지보다 효율적인 데이터 형식을 사용할 수 있습니다. 그러나 255 자의 홀수 길이 제한은 Postgres의 성능에 전혀 영향을 미치지 않습니다.


1
varchar(255)예를 들어 , SQL Server에는 숨겨진 최적화가 없습니다 varchar(260). SQL Server 6.x에는 그러한 문제가 있었지만 오랫동안 사실이 아니 었습니다.
a_horse_with_no_name

@ a_horse_with_no_name : 감사합니다.
Erwin Brandstetter

죄송이 동의 너무 오래내어, 그 프로젝트의 개발에 느린있었습니다)
크리스 Cirefice

이 답변이 여전히 Postgres 10에 유효합니까?
Matty

1
@Matty : 여전히 유효합니다. 그리고 pg 11에서도 아직 아무것도 바뀌지 않았습니다.
Erwin Brandstetter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.