PostgreSQL에서 부호없는 정수를 사용할 수없는 이유는 무엇입니까?


113

이 게시물 ( MySQL에서 tinyint, smallint, mediumint, bigint 및 int의 차이점은 무엇입니까? )을보고 PostgreSQL이 부호없는 정수를 지원하지 않는다는 것을 깨달았습니다.

누구든지 그 이유를 설명하는 데 도움을 줄 수 있습니까?

대부분의 경우 MySQL에서 자동 증분 기본 키로 부호없는 정수를 사용합니다. 이러한 디자인에서 MySQL에서 PostgreSQL로 데이터베이스를 이식 할 때 어떻게 극복 할 수 있습니까?

감사.


아직은 아니지만 곧 PostgreSQL 로의 전환을 고려하고 있습니다.
Adrian Hoe

4
나는 이것이 특정 결정이 내려진 이유를 묻는 가장 좋은 장소라고 생각하지 않습니다. PostgreSQL 메일 링 목록 중 하나가 더 적합 할 수 있습니다. 값을 자동으로 늘리려면 serial(1 ~ 2147483647) 또는 bigserial(1 ~ 9223372036854775807)을 사용하세요. 부호있는 64 비트 정수는 아마도 충분한 공간을 제공합니다.
MU이 너무 짧

4
감사합니다 @muistooshort. 이것이 주요 문제에 대한 답입니다. 그러나 자동 증분 또는 기본 키가 아닌 부호없는 정수 유형은 어떻습니까? 0에서 2 ^ 32 범위의 부호없는 정수를 저장하는 열이 있습니다.
Adrian Hoe

4
PostgreSQL 문서 ( postgresql.org/docs/current/interactive/index.html ) 를 빠르게 실행하면 PostgreSQL 이 무엇을 할 수 있는지 더 잘 이해하는 데 도움이 될 수 있습니다. 내가 요즘 MySQL을 사용하는 유일한 이유는 이미 많은 투자가 있었기 때문입니다. PostgreSQL은 빠르고 유용한 기능을 탑재하고 있으며 데이터에 대해 편집증이있는 사람들에 의해 구축되었습니다. IMO : 물론
MU이 너무 짧

포인터에 대해 다시 @muistooshort에게 감사드립니다.
아드리안 괭이

답변:


47

postgresql에 서명되지 않은 유형이없는 이유는 이미 답변되어 있습니다. 그러나 서명되지 않은 유형에는 도메인을 사용하는 것이 좋습니다.

http://www.postgresql.org/docs/9.4/static/sql-createdomain.html

 CREATE DOMAIN name [ AS ] data_type
    [ COLLATE collation ]
    [ DEFAULT expression ]
    [ constraint [ ... ] ]
 where constraint is:
 [ CONSTRAINT constraint_name ]
 { NOT NULL | NULL | CHECK (expression) }

도메인은 유형과 비슷하지만 추가 제약이 있습니다.

구체적인 예를 들어 다음을 사용할 수 있습니다.

CREATE DOMAIN uint2 AS int4
   CHECK(VALUE >= 0 AND VALUE < 65536);

다음은 유형을 남용하려고 할 때 psql이 제공하는 것입니다.

DS1 = # 선택 (346346 :: uint2);

오류 : uint2 도메인의 값이 "uint2_check"검사 제약 조건을 위반합니다.


그러나 서명되지 않은 열을 원할 때마다이 도메인을 사용하면 INSERT / UPDATE에 오버 헤드가 발생한다고 생각합니다. 정말로 필요한 곳 ​​(드문 경우)에 이것을 사용하고 데이터 유형이 우리가 원하는 하한을 두지 않는다는 생각에 익숙해지는 것이 좋습니다. 결국 논리적 관점에서 볼 때 일반적으로 무의미한 상한선도 설정합니다. 숫자 유형은 우리의 애플리케이션 제약을 강제하기위한 것이 아닙니다.
Federico Razzoli

이 접근 방식의 유일한 문제점은 사용되지 않는 15 비트 데이터 스토리지를 "낭비"한다는 것입니다. 수표는 또한 약간의 효율성을 요구합니다. 더 나은 해결책은 Postgres가 unsigned를 첫 번째 클래스 유형으로 추가하는 것입니다. 2 천만 개의 레코드가 있고 이와 같이 인덱싱 된 필드가있는 테이블에서 사용되지 않는 비트에 40MB의 공간을 낭비하고 있습니다. 다른 20 개의 테이블에서이를 악용하는 경우 이제 800MB의 공간을 낭비하게됩니다.
tpartee

85

SQL 표준이 아니므로이를 구현하려는 일반적인 충동은 낮습니다.

다른 정수 유형이 너무 많으면 유형 확인 시스템이 더 취약 해 지므로 혼합에 더 많은 유형을 추가하는 데 약간의 저항이 있습니다.

즉, 할 수없는 이유가 없습니다. 그것은 단지 많은 일입니다.


35
이 질문은 내가 그것을 고칠에 착수했다고 인기 충분하다 : github.com/petere/pguint
피터 Eisentraut

부호없는 정수 리터럴에 대한 입력 / 출력 변환이 있으면 매우 유용합니다. 또는 to_char패턴 일 수도 있습니다.
Bergi

37

CHECK 제약 조건을 사용할 수 있습니다. 예 :

CREATE TABLE products (
    product_no integer,
    name text,
    price numeric CHECK (price > 0)
);

또한, PostgreSQL은있다 smallserial, serialbigserial자동 증가에 대한 유형.


2
한 가지 언급 할 사항은 CHECK를 사용하는 열에 NULL을 사용할 수 없다는 것입니다.
Minutis 2017 년

1
@Minutis 당신이 당신이이 X 질수있는 것은 NULL 또는 4 내지 40 X는
jgmjgm

그리고 이것은 unsigned int와 같은 해상도를 제공하지 않습니다. unsigned int는까지 올라가고 2^32-1, signed int는까지 올라갈 수 2^31-1있습니다.
JukesOnYou

2
NULLCHECK완전히 직교한다. NULL/ NOT NULL열이 있거나 없을 수 있습니다 CHECK. 그냥에서 문서에 따라, 점에 유의 postgresql.org/docs/9.4/ddl-constraints.html , CHECK당신이 정말로 다음, 널 (null)을 방지 사용하고자 그렇다면, TRUE로 NULL 평가하여 반환 NOT NULL하는 대신 (또는 이외에 CHECK).
flaviovs

CHECK를 사용하면 ipv4 주소를 저장할 수 없습니다 integer(최소한 무작위로 양수 또는 음수로 변경하지 않고서는 안됩니다.)
hanshenrik

5

DOMAINS에 대한 이야기는 흥미롭지 만 해당 질문의 유일한 출처와 관련이 없습니다. unsigned int에 대한 욕구는 동일한 비트 수로 int의 범위를 두 배로 늘리는 것입니다. 이는 음수를 제외하려는 욕구가 아니라 효율성 인수입니다. 모두가 검사 제약 조건을 추가하는 방법을 알고 있습니다.

누군가가 그것에 대해 물었을 때 , Tome Lane은 다음과 같이 말했습니다.

기본적으로 많은 기존 응용 프로그램을 손상시키지 않는 숫자 프로모션 계층 구조에이를 맞추는 방법을 찾을 수 없으면 이런 일이 발생할 가능성이 없습니다. 우리는 기억이 작용한다면 이것을 한 번 이상 살펴 보았지만 POLA를 위반하지 않는 것처럼 보이는 실행 가능한 디자인을 찾지 못했습니다.

"POLA"는 무엇입니까? Google은 의미없는 10 개의 결과를주었습니다 . 정치적으로 잘못된 생각인지, 따라서 검열되었는지 확실하지 않습니다. 이 검색어가 결과를 산출하지 못하는 이유는 무엇입니까? 도대체 무엇이.

별다른 문제없이 unsigned int를 확장 유형으로 구현할 수 있습니다. C- 함수를 사용하면 성능 저하가 전혀 발생하지 않습니다. PgSQL에는 문자열을 리터럴로 해석하는 쉬운 방법이 있기 때문에 구문 분석기를 확장하여 리터럴을 처리 할 필요가 없습니다. '4294966272':: uint4를 리터럴로 작성하면됩니다. 캐스트도 큰 문제는 아닙니다. 범위 예외를 수행 할 필요조차 없습니다. '4294966273':: uint4 :: int의 의미를 -1024로 처리하면됩니다. 또는 오류를 던질 수 있습니다.

내가 이것을 원했다면 내가했을 것입니다. 그러나 SQL의 반대편에서 Java를 사용하고 있기 때문에 Java에는 부호없는 정수가 없기 때문에 가치가 거의 없습니다. 그래서 나는 아무것도 얻지 못합니다. bigint 열에서 BigInteger를 가져 오면 길이가 길 때 이미 짜증이납니다.

또 다른 한가지, 32 비트 또는 64 비트 유형을 저장할 필요가 있다면 PostgreSQL int4 또는 int8을 각각 사용할 수 있습니다. 다만 자연 순서 나 산술이 안정적으로 작동하지 않는다는 점만 기억하면됩니다. 그러나 저장 및 검색은 그 영향을받지 않습니다.


다음은 간단한 unsigned int8을 구현하는 방법입니다.

먼저 사용하겠습니다

CREATE TYPE name (
    INPUT = uint8_in,
    OUTPUT = uint8_out
    [, RECEIVE = uint8_receive ]
    [, SEND = uint8_send ]
    [, ANALYZE = uint8_analyze ]
    , INTERNALLENGTH = 8
    , PASSEDBYVALUE ]
    , ALIGNMENT = 8
    , STORAGE = plain
    , CATEGORY = N
    , PREFERRED = false
    , DEFAULT = null
)

최소 2 개의 기능 uint8_inuint8_out먼저 정의해야합니다.

CREATE FUNCTION uint8_in(cstring)
    RETURNS uint8
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION uint64_out(complex)
    RETURNS cstring
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;

이것을 C uint8_funcs.c에서 구현해야합니다. 그래서 여기에서 복잡한 예제를 사용 하여 간단하게 만듭니다.

PG_FUNCTION_INFO_V1(complex_in);

Datum complex_in(PG_FUNCTION_ARGS) {
    char       *str = PG_GETARG_CSTRING(0);
    uint64_t   result;

    if(sscanf(str, "%llx" , &result) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                 errmsg("invalid input syntax for uint8: \"%s\"", str)));

    return (Datum)SET_8_BYTES(result);
}

아 글쎄, 아니면 그냥 이미 끝났어 .


1
나는 POLA가 "최소한 경악의 원칙"이라고 생각합니다. 변경이 예상치 못한 방식으로 기존 동작을 변경할 가능성이 있음을 시사합니다.
Doctor Eval

1

최신 문서에 따르면 singed integer는 지원되지만 테이블에는 unsigned integer가 없습니다. 그러나 직렬 유형은 0이 아닌 1에서 시작한다는 점을 제외하면 unsigned와 유사합니다. 그러나 상한은 singed와 같습니다. 따라서 시스템에는 서명되지 않은 지원이 없습니다. Peter가 지적했듯이 서명되지 않은 버전을 구현할 수있는 문이 열려 있습니다. 코드를 많이 업데이트해야 할 수도 있습니다. C 프로그래밍 작업을 통해 얻은 작업이 너무 많습니다.

https://www.postgresql.org/docs/10/datatype-numeric.html

integer     4 bytes     typical choice for integer  -2147483648 to +2147483647
serial  4 bytes     autoincrementing integer    1 to 2147483647

0

Postgres에는 많은 사람들에게 알려지지 않은 부호없는 정수 유형이 OID있습니다.

oid유형은 현재 부호없는 4 바이트 정수로 구현됩니다. […]

oid유형 자체는 비교를 제외하고는 몇가지 연산을. 그러나 정수로 캐스트 한 다음 표준 정수 연산자를 사용하여 조작 할 수 있습니다. (이 작업을 수행하는 경우 서명 된 대 서명되지 않은 혼동 가능성에주의하십시오.)

그러나 숫자 유형 이 아니며 산술 (또는 비트 단위 연산)을 수행하려는 시도는 실패 할 것입니다. 또한 4 바이트 ( INTEGER)에 해당하는 8 바이트 ( BIGINT) 부호없는 유형 이 없습니다 .

따라서 이것을 직접 사용하는 것은 좋은 생각이 아니며 Postgresql 데이터베이스 디자인에서 직렬 기본 키에 대해 항상 INTEGER또는 BIGINT열을 사용해야한다는 다른 모든 답변에 동의 합니다. 전체 도메인을 소진하려면 ( ) 을 감싸십시오 .MINVALUECYCLE

그러나 다른 DBMS에서 마이그레이션하는 것과 같이 입력 / 출력 변환에 매우 유용합니다. 2147483648정수 열에 값 을 삽입하면 " 오류 : 정수 범위를 벗어남 "이 발생하지만 표현식을 사용하면 2147483648::OID잘 작동합니다.
마찬가지로를 사용하여 정수 열을 텍스트로 선택하면 mycolumn::TEXT어느 시점에서 음수 값을 얻지 만 mycolumn::OID::TEXT항상 자연수를 얻습니다.

dbfiddle.uk에서 예제를 참조하십시오 .


작업이 필요하지 않은 경우 OID 사용의 유일한 가치는 정렬 순서가 작동한다는 것입니다. 그것이 당신이 필요하다면 괜찮습니다. 그러나 곧 누군가가 uint8을 원할 것이고 그들도 잃어 버릴 것입니다. 결론은 32 비트 또는 64 비트 값을 저장하려면 각각 int4 및 int8을 사용할 수 있으며 작업에주의해야합니다. 그러나 확장을 작성하는 것은 쉽습니다.
Gunther Schadow
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.