고정 크기 필드에서 CHAR vs VARCHAR을 사용하면 성능에 어떤 영향을 미칩니 까?


58

MD5 해시를 저장하는 인덱스 열이 있습니다. 따라서 열은 항상 32 자 값을 저장합니다. 어떤 이유로 든 이것은 char이 아닌 varchar로 만들어졌습니다. 데이터베이스를 문자로 변환하기 위해 데이터베이스를 마이그레이션하는 데 어려움이 있습니까? 이것은 InnoDB가 설치된 MySQL 5.0에 있습니다.


6
경고이 질문과 답변은 InnoDB와 utf8이 기본값이되기 전에 작성되었습니다.
Rick James

답변:


56

비슷한 질문을하기 전에

MySQL VARCHAR 크기의 성능 영향

여기 내 대답의 발췌가 있습니다.

CHAR 대 VARCHAR 사용의 장단점을 인식해야합니다

CHAR 필드를 사용하면 할당하는 것이 정확히 얻는 것입니다. 예를 들어, CHAR (15)는 필드에 문자를 배치하는 방법에 관계없이 15 바이트를 할당하고 저장합니다. 데이터 필드의 크기를 완전히 예측할 수 있으므로 문자열 조작이 간단하고 간단합니다.

VARCHAR 필드를 사용하면 완전히 다른 이야기를 얻을 수 있습니다. 예를 들어 VARCHAR (15)는 실제로는 최대 16 바이트, 데이터의 경우 최대 15 바이트, 데이터의 길이를 저장하기 위해 최소 1 개의 추가 바이트를 동적으로 할당합니다. 저장할 문자열 'hello'가 6 바이트가 아닌 경우 5가 아닙니다. 문자열 조작은 항상 모든 형태의 길이 검사를 수행해야합니다.

다음 두 가지 작업을 수행하면 절충이 더 분명해집니다. 1. 수백만 또는 수십억 개의 행 저장 2. CHAR 또는 VARCHAR 인 색인화 열

TRADEOFF # 1 가변 길이 데이터는 더 작은 행을 생성하므로 더 작은 실제 파일을 생성하므로 VARCHAR은 이점을 갖습니다.

TRADEOFF # 2 CHAR 필드는 고정 필드 너비로 인해 문자열 조작이 덜 필요하므로 CHAR 필드에 대한 인덱스 조회는 VARCHAR 필드에 비해 평균 20 % 빠릅니다. 이것은 내 추측에 해당되지 않습니다. MySQL Database Design and Tuning 책은 이것을 증명하기 위해 MyISAM 테이블에서 놀라운 것을 수행했습니다. 이 책의 예는 다음과 같은 것을 수행했습니다.

ALTER TABLE tblname ROW_FORMAT=FIXED;

이 지시문은 모든 VARCHAR이 CHAR로 작동하도록합니다. 나는 2007 년 이전 직장에서이 작업을 수행했으며 300GB 테이블을 가져 와서 다른 것을 변경하지 않고 인덱스 조회를 20 % 늘 렸습니다. 출판 된대로 작동했습니다. 그러나 거의 두 배 크기의 테이블을 만들었지 만 단순히 트레이드 오프 # 1로 돌아갑니다.

저장된 데이터를 분석하여 MySQL이 열 정의에 권장하는 것을 확인할 수 있습니다. 테이블에 대해 다음을 실행하십시오.

SELECT * FROM tblname PROCEDURE ANALYSE();

그러면 전체 테이블을 순회하며 포함 된 데이터, 최소 필드 값, 최대 필드 값 등을 기준으로 모든 열에 대한 열 정의를 권장합니다. 때로는 CHAR 대 VARCHAR을 계획 할 때 상식을 사용해야합니다. 다음은 좋은 예입니다.

IP 주소를 저장하는 경우 해당 열의 마스크는 최대 15 자 (xxx.xxx.xxx.xxx)입니다. CHAR(15)IP 주소의 길이는 그다지 다르지 않으며 추가 바이트로 제어되는 문자열 조작의 복잡성이 증가하기 때문에 하트 비트에서 바로 뛰어 넘을 것입니다. 당신은 여전히 ​​그런 PROCEDURE ANALYSE()열에 대해 반대 할 수 있습니다 . VARCHAR을 권장 할 수도 있습니다. 이 경우 내 돈은 여전히 ​​VARCHAR보다 CHAR에 있습니다.

CHAR 대 VARCHAR 문제는 적절한 계획을 통해서만 해결할 수 있습니다. 큰 힘으로 큰 책임이 따릅니다 (진실이지만 사실).

최신 정보

MD5에 관해서 strlen는 전체 행 형식을 전환 할 때 내부 계산을 제거해야합니다. 필드 정의를 변경할 필요가 없습니다.

MD5 키가 유일한 VARCHAR이면, 키 행을 사용하여 테이블 행 형식을 fixed로 변환합니다 . 많은 수의 다른 VARCHAR 필드가있는 경우에도 도움이됩니다. 그 대가로 테이블의 크기가 약 두 배로 확장되었습니다. 그러나 추가 조정 없이도 쿼리 속도가 약 20 % 증가합니다.


1
IP 주소에 char (4) 또는 부호없는 정수 와 같은 것을 사용한다고 생각 합니다.
Jack Douglas

@JackPDouglas 그 점이 맞습니다.
RolandoMySQLDBA

어쨌든 고정 길이로 저장된 색인이 없습니까? 스토리지 형식을 고정 길이로 변경하여 인덱스 조회를 개선하는 방법을 얻지 못했습니다. 테이블 스캔이 개선되었음을 의미합니까?
Marcus Adams

1
@JackDouglas, 왜 bitbinary?
Pacerier

@Pacerier가 더 나을 것입니다, 동의합니다 :)
Jack Douglas

19

로 변환하여 값당 1 바이트 또는 약 3 %를 절약하는 것처럼 보입니다 char. 어쨌든 MD5 를 16 진수 로 저장하면 그만한 가치가 없습니다 binary. 대신에 50 %를 절약 할 수 있습니다.

멀티 바이트 문자 집합을 사용하는 경우 32 바이트 이상을 사용할char(32) 수 있다고 지적한 Ovais (주석 참조)에게 감사합니다 .

unhex16 진수 문자열을 이진수로 변환하는 함수를 사용해야 함을 지적한 Rick James에게 감사합니다 .

create table foo(bar varbinary(100));
insert into foo(bar) values(md5('a')); 
insert into foo(bar) values(unhex(md5('a'))); 
select length(bar) from foo;
| 길이 (bar) |
| ---------- : |
| 32 |
| 16 |

db <> 바이올린 여기


바이너리로 바꾸는 것이 좋습니다.
RThomas 2016 년

이것을 바이너리로 변환 할 계획입니다. 그래도 그것에 대해 생각하기 때문에, 인코딩이 utf-8이기 때문에 바이트 또는 문자를 사용하는지 여부에 따라 크기가 다르지 않아야합니다. 아니면 내가 틀렸어?
Jason Baker

@Jason-인코딩이 적용되지 않거나 binary오해 되었습니까?
잭 더글러스

3
문자 집합이 utf-8 인 char (32) 열의 경우 모든 값에는 저장시 32x3 바이트가 필요합니다. MD5 해시 값을 utf-8로 설정해야하는 이유는 무엇입니까? binary (32)로 변환하려면 값당 32 바이트가 필요합니다.
ovais.tariq

1
를 사용 BINARY하지 않으면로 변경하는 것이 거의 없습니다 UNHEX(). 즉 당신이 저장할 수있다 UNHEX(MD5(x))16 바이트로 BINARY(16)저장 비해 상당한 공간을 절약하기 MD5(x)CHAR(32) CHARACTER SET ascii.
Rick James

15

내 의견으로는 바꿀 가치가 없습니다. 여기에서 문서를 살펴보면 두 문서의 차이점을 설명해야합니다. 사용 시나리오에서 행 크기와 관련된 추가 오버 헤드에 대해 염려하지 않는 한 실제로 다른 것에 비해 큰 이점을 제공하지 않습니다.

http://dev.mysql.com/doc/refman/5.0/en/char.html

또한 위에 링크 된 문서에 대한 첫 번째 주석을 참고하십시오 ... "CHAR은 전체 레코드의 크기가 고정 된 경우에만 액세스 속도를 높입니다. 즉, 가변 크기 개체를 사용하는 경우 모든 개체를 만들 수도 있습니다. VARCHAR도 포함하는 테이블에서 CHAR을 사용하면 속도가 나지 않습니다. "


"스피드 업"은 InnoDB가 아닌 MyISAM에 적용됩니다.
Rick James
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.