15.2 숫자
- 숫자를 저장하는 타입은 크게 값의 정확도에 따라 참값과 근사값 타입으로 나눌 수 있다.
-
- 참값은 소수점 이하 값의 유무에 관계없이 정확히 그 값을 그대로 유지하는 것을 의미한다. 참값을 관리하는 데이터타입으로는 INTEGER를 포함해 INT로 끝나는 타입과 DECIMAL이 있다.
- 근사값은 흔히 부동 소수점이라고 불리는 값을 의미하며, 처음 칼럼에 저장한 값과 조회된 값이 정확하게 일치하지 않고 최대한 비슷한 값을 관리하는 것을 의미한다. 근사값을 관리하는 타입으로는 float와 double가 있다.
- 값이 저장되는 포맷에 따라 십진 표기법과 이진 표기법으로 나눠 볼 수 있다.
-
- 이진 표기법 : 흔히 프로그래밍 언어에서 사용하는 정수나 실수 타입을 의미한다. 이진 표기법은 한 바이트로 한자리 또는 두 자리 숫자만 저장하는 것이 아니라 28까지의 숫자를 저장할 수 있는 특징이 있기 때문에 숫자 값을 적은 메모리나 디스크 공간에 저장할 수 있다. MySQL의 INTEGER나 BIGINT 등 대부분의 숫자 타입은 모두 이진 표기법을 사용한다.
- 십진 표기법 : 숫자 값의 각 자리 값을 표현하기 위해 4비트나 한 바이트를 사용해서 표기하는 방법이다. 디스크나 메모리에 십진 표기법으로 저장된다는 것을 의미한다. MySQL의 십진 표기법을 사용하는 타입은 DECIMAL뿐이며, DECIMAL 타입은 금액(돈)처럼 정확하게 소수점까지 관리돼야 하는 값을 저장할 때 사용한다. 또한 DECIMAL 타입은 65자리 숫자까지 표현할 수 있으므로 BIGINT로도 저장할 수 없는 값을 저장할 때 사용된다.
15.2.1 정수
- DECIMAL 타입을 제외하고 정수를 저장하는 데 사용할 수 있는 데이터 타입으로는 5가지가 있다. 저장 가능한 숫자 값의 범위만 다를 뿐 다른 차이는 거의 없다.
타입 | 필요 저장 공간 | 저장 가능한 수의 범위 |
---|---|---|
TINYINT | 1바이트 | ~128 ~ 127 (0 ~ 255) |
SMALLINT | 2바이트 | -32768 ~ 32767 ( 0~ 65535 ) |
MEDIUMINT | 3바이트 | -8388608 ~ 8388607 ( 0 ~ 16777215 ) |
INTEGER | 4바이트 | -2147483648 ~ 2147483647 ( 0 ~ 4294967295 ) |
BIGINT | 8바이트 | -9223372036854775808 ~ 9223372036854775807 ( 0 ~ 18446744073709551615 ) |
- 정수 타입은 UNSIGNED라는 컬럼 옵션을 사용할 수 있다. 정수 칼럼을 생성할 때 UNSIGNED 옵션을 명시하지 않으면 기본적으로 음수와 양수를 동시에 저장할 수 있는 숫자 타입(SIGNED)이 된다. 하지만 UNSIGNED 옵션을 정의한 정수 칼럼은 0보다 큰 양의 정수만 저장할 수 있게 되면서 저장할 수 있는 최댓값은 SIGNED 타입보다 2배가 더 커진다.
15.2.2 부동소수점
- MySQL에서는 부동 소수점을 저장하기 위해 Float와 Double 타입을 사용할 수 있다. 부동 소수점이라는 이름에서 부동은 소수점의 위치가 고정적이지 않다는 의미인데, 숫자 값의 길이에 따라 유효 범위의 소수점 자리수가 바뀐다. 그래서 부동 소수점을 사용하면 정확한 유효 소수점 값을 식별하기 어렵고 그 값을 따져서 크다 작다 비교를 하기가 쉽지 않다.
- 부동 소수점은 근사값을 저장하는 방식라서 동등 비교는 사용할 수 없다.
Float
- 일반적으로 정밀도를 명시하지 않으면 4바이트를 사용해 유효 자리 수를 8개까지 유지하며, 정밀도가 명시된 경우에는 최대 8바이트까지 저장 공간을 사용할 수 있다.
Double
- 8바이트의 저장 공간을 필요로 하며 최대 유효 자리 수를 16개까지 유지할 수 있다.
만약 부동 소수점 값을 저장해야 한다면 유효 소수점의 자리수만큼 10을 곱해서 정수로 만들어 그 값을 정수 타입의 칼럼에 저장하는 방법도 생각해볼 수 있다. 에를 들어 소수점 4자리까지 유효한 GPS 정보를 저장한다고 했을 때 소수점으로 된 좌표 값에 10000을 곱해서 저장하고 조회할 때는 10000으로 나눈 결과를 사용하면 된다.
15.2.3 DECIMAL
- 부동 소수점에서 유효 범위 이외의 값은 가변적이므로 정확한 값을 보장할 수 없다. 즉, 금액이나 대출이자 등과 같이 고정된 소수점까지만 정확하게 관리해야 할 때는 FLOAT나 DOUBLE 타입을 사용해서는 안된다. 그래서 소수점의 위치가 가변적이지 않은 고정 소수점 타입을 위해 DECIMAL 타입을 제공한다. 비슷한 성격의 타입으로 NUMERIC 타입이 있다. MySQL에서는 NUMERIC와 DECIMAL은 내부적으로 같은 방식으로 처리되므로 동의어 정도로 이해하면 된다.
- MySQL에서 소수점 이하의 값까지 정확하게 관리하려면 DECIMAL이나 NUMERIC 타입을 이용해야 한다. DECIMAL 타입은 숫자 하나를 저장하는 데 1/2바이트가 필요하므로 한 자리나 두 자리 수를 저장하는 데 1바이트가 필요하고 세 자리나 네 자리 숫자를 저장하는 데는 2바이트가 필요하다. 즉 DECIMAL로 저장하는 (숫자의 자리수)/2의 결과값을 올림 처리한 만큼의 바이트 수가 필요하다.
- 결론적으로 소수가 아닌 정수 값을 관리하기 위해 DECIMAL이나 NUMERIC 타입을 사용하는 것은 성능상으로나 공간 사용면에서 좋지 않다. 단순히 정수를 관리하고자 한다면 INTEGER나 BIGINT를 사용하는 것이 좋다.
15.2.4 정수 타입의 컬럼을 생성할 때의 주의사항
- 부동 소수점이나 DECIMAL 타입을 이용해 칼럼을 정의할 때는 타입의 이름 뒤에 괄호로 정밀도를 표시하는 것이 일반적이다.
-
- ex) DECIMAL(20, 5)라고 정의하면 정수부를 15(=20-5)자리까지, 그리고 소수부를 5자리까지 저장할 수 있는 DECIMAL 타입을 생성한다.
- ex) DECIMAL(20)이라고 정의하는 경우에는 소수부 없이 정수부만 20자리까지 저장할 수 있는 타입의 컬럼을 생성한다.
- float이나 double 타입은 저장 공간의 크기가 고정형이므로 정밀도를 조절한다고 해서 저장 공간의 크기가 바뀌는 것은 아니다. 하지만 DECIMAL 타입은 저장 공간의 크기가 가변적인 데이터 타입이어서 DECIMAL 타입에 사용하는 정밀도는 저장 가능한 자리 수를 결정함과 동시에 저장 공간의 크기까지 제한한다.
ZEROFILL : 실질 숫자 값의 앞쪽에 0을 패딩해서 가져올 것인지를 설정하는 옵션이다. ZEROFILL을 사용할 때 몇 자리까지 패딩할지를 결정하는 것이 정수 타입 뒤의 명시된 숫자 크기의 역할이다.
정수 타입 뒤의 길이 지정은 ZEROFILL 옵션이 없으면 아무런 의미가 없다. ZEROFILL 옵션이 사용되면 자동으로 그 칼럼의 타입은 양의 숫자만 저장할 수 있는 UNSIGNED 타입이 되어 버리기 때문에 주의해야 한다.
15.2.5 자동 증가 옵션 사용
- 테이블의 프라이머리 키를 구성하는 칼럼의 크기가 너무 크거나 프라이머리 키로 사용할 만한 칼럼이 없을 때는 숫자 타입의 칼럼에 자동 증가 옵션을 사용해 인조 키를 생성할 수 있다.
- MySQL 서버의 auto_increment_increment와 auto_increment_offset 시스템 설정을 이용해 AUTO_INCREMENT 칼럼의 자동 증가 값이 얼마씩 증가될지 변경할 수 있다. 만약 auto_increment_offset을 5로 auto_increment_increment를 10으로 변경하면 자동 생성되는 값은 5, 15, 25,…와 같이 증가한다.
MyISAM 스토리지 엔진을 사용하는 테이블에서는 자동 증가 옵션이 사용된 칼럼이 프라이머리 키나 유니크 키의 아무 위치에나 사용될 수 있다.
InnoDB 스토리지 엔진을 사용하는 테이블에서는 반드시 AUTO_INCREMENT 칼럼이 프라이머리 키 또는 유니크 키 중 적어도 하나의 인덱스에서는 제일 앞에 위치해야 한다.
- AUTO_INCREMENT 칼럼은 테이블당 단 하나만 사용할 수 있다. AUTO_INCREMENT 칼럼이 없는 테이블에 새로운 AUTO_INCREMENT 칼럼을 추가하면 새로 추가된 칼럼은 1부터 자동으로 증가된 값이 할당된다. AUTO_INCREMENT 칼럼의 현재 증가 값은 테이블의 메타 정보에 저장돼 있는데, 다음 증가 값이 얼마인지는 “SHOW CREATE TABLE tb_autoinc_myisam;” 명령으로 조회할 수 있다.
CREATE TABLE tb_autoinc_innodb{
fd_pk1 INT(11) NOT NULL DEFAULT '0',
fd_pk2 INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (fd_pk1, fd_pk2),
UNIQUE KEY ux_fdpk2 (fd_pk2)
} ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8