Trois types avec PostgreSQL
PostgreSQL propose 3 types de données pour stocker les entiers, conformément au standard SQL : SMALLINT (INT2), INTEGER (INT, INT4) et BIGINT (INT8).
-
Le type SMALLINT permet de stocker, sur 2 octets, des entiers entre -32768 et 32767
-
Le type INTEGER permet de stocker, sur 4 octets, des entiers entre -2147483648 et +2147483647
-
Le type BIGINT permet de stocker, sur 8 octets, des entiers entre -9223372036854775808 et +9223372036854775807
Démonstration avec PostgreSQL 10 et le type smallint :
select version();
version
----------------------------------------------------------------------------------------------------------------
PostgreSQL 10.0 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609, 64-bit
(1 ligne)
create table t1(c1 smallint);
CREATE TABLE
insert into t1(c1) values(-32769);
ERREUR: smallint en dehors des limites
insert into t1(c1) values(-32768);
INSERT 0 1
insert into t1(c1) values(32767);
INSERT 0 1
insert into t1(c1) values(32768);
ERREUR: smallint en dehors des limites
insert into t1 values(1.1);
INSERT 0 1
insert into t1 values(1.6);
INSERT 0 1
select * from t1;
c1
--------
-32768
32767
1
2
(4 lignes)
Il convient simplement de choisir le bon type de données en fonction du besoin fonctionnel afin de ne pas perdre despace et donc de performance.
Pour optimiser au maximum lespace, vous pouvez aller jusquà prendre en compte la notion dalignement au niveau du stockage, propre à PostgreSQL. Sans entrer dans les détails, dans lordre de création des colonnes dune table, placez dabord les bigint puis les integer puis les smallint. PostgreSQL gérera peut-être automatiquement cet aspect dans de futures versions.
Et si on part dOracle ?
Oracle Database stocke essentiellement les valeurs numériques, dont font partie les valeurs entières, dans un type appelé NUMBER. Il est possible dutiliser les syntaxes du standard SQL, SMALLINT et INTEGER (mais PAS BIGINT), mais au final vous obtiendrez des NUMBER(38).
Démonstration avec Oracle Database 12.2.0.1 :
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
create table t1(c1 smallint);
Table created.
desc t1;
Name Null? Type
----------------------------------------- -------- ----------------------------
C1 NUMBER(38)
insert into t1(c1) values(-32769);
1 row created.
insert into t1(c1) values(-32768);
1 row created.
insert into t1(c1) values(32767);
1 row created.
insert into t1(c1) values(32768);
1 row created.
insert into t1 values(1.1);
1 row created.
insert into t1 values(1.6);
1 row created.
select * from t1;
C1
----------
-32769
-32768
32767
32768
1
2
6 rows selected.
create table t2(c1 integer);
Table created.
desc t2;
Name Null? Type
----------------------------------------- -------- ----------------------------
C1 NUMBER(38)
create table t3(c1 bigint);
create table t3(c1 bigint)
*
ERROR at line 1:
ORA-00902: invalid datatype
create table t4(c1 number(5));
Table created.
desc t4;
Name Null? Type
----------------------------------------- -------- ----------------------------
C1 NUMBER(5)
insert into t4 values(99999);
1 row created.
insert into t4 values(100000);
insert into t4 values(100000)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
Si vous voulez limiter la taille des entiers avec Oracle, ce nest pas en créant des SMALLINT ou des INTEGER que vous y parviendrez. Il est en revanche possible de créer des number(N). En pratique, cest très rarement utilisé car, avec ce type NUMBER, le stockage est alloué en fonction de la taille (précision) du nombre à stocker. Utiliser un number(3) ne prendra pas moins de place quutiliser un number(38) pour stocker des entiers jusquà 999. Le NUMBER dOracle Database est plus proche du NUMERIC de PostgreSQL, un type standard SQL.
Pourquoi ne pas utiliser NUMERIC pour stocker les entiers sous PostgreSQL alors ? Pour des raisons de performance. Démonstration avec PostgreSQL 10 :
select version();
version
----------------------------------------------------------------------------------------------------------------
PostgreSQL 10.0 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609, 64-bit
(1 ligne)
create table t1(c1 integer);
CREATE TABLE
insert into t1 select random()*1000000 from generate_series(1,1000000,1);
INSERT 0 1000000
select avg(c1*10/10) from t1 ;
avg
---------------------
499914.986444000000
(1 ligne)
Temps : 62,939 ms
...
Temps : 65,357 ms
...
Temps : 62,327 ms
create table t1_bis as select * from t1 order by random();
SELECT 1000000
select count(*) from t1 natural join t1_bis;
count
---------
2001300
(1 ligne)
Temps : 425,501 ms
...
Temps : 424,013 ms
...
Temps : 424,013 ms
create table t2(c1 numeric);
CREATE TABLE
create table t2_bis(c1 numeric);
CREATE TABLE
insert into t2 select * from t1;
INSERT 0 1000000
insert into t2_bis select * from t1_bis;
INSERT 0 1000000
select avg(c1*10/10) from t2 ;
avg
-----------------------------
499914.98644400000000000000
(1 ligne)
Temps : 154,365 ms
...
Temps : 146,062 ms
...
Temps : 148,313 ms
select count(*) from t2 natural join t2_bis;
count
---------
2001300
(1 ligne)
Temps : 528,645 ms
...
Temps : 514,588 ms
...
Temps : 525,206 ms
Confirmation avec cet exemple, PostgreSQL permet doptimiser les opérations et tests sur les entiers grâce aux types dédiés SMALLINT, INTEGER, BIGINT. Même si ce nest pas obligatoire au niveau fonctionnel, il faut donc idéalement sinterroger sur chaque colonne numérique pour optimiser le stockage et les performances lors de la migration dOracle Database vers PostgreSQL.