Spesso ci si dimentica che, nella gestione dei campi contatore, abbiamo a disposizione anche i numeri minori di zero.
Spesso, se ci si trova nell'eventualità di dover memorizzare 3 miliardi e mezzo di righe, si preferisce utilizzare, sulla colonna contatore autoincrementante, un tipo BIGINT.
Perchè?
Perchè il tipo INT arriva, all’estremo positivo, fino a 2.147.483.647
Bene. E' la parte negativa?
Perchè siamo abituati a scrivere qualcosa come questo?
create table test
(
idRecord int primary key identity (1,1),
valore varchar(1)
)
go
e non qualcosa come questo?
create table test
(
idRecord int primary key identity (-2147483648,1),
valore varchar(1)
)
go
La domanda che mi faccio spesso è: perchè i numeri negativi non piacciono?
Non sono forse cifre come tutte le altre?
Si tratta solo di leggibilità?
Si ha paura di dire "guarda la riga con ID = -1.235.887.112 ?"
Il punto è sempre e solo questo: I/O.
Dobbiamo risparimiare storage. Non perchè costi lo spazio di per sè (non si parla di euro per hard disk), ma perchè costa tantissimo utilizzarlo (leggerlo / scriverlo).
Se utilizzo un BIGINT significa utilizzare 4 byte in più.
Ovvero, con tre miliardi di righe significa utilizzare 12 miliardi di byte, ovvero più di 11 Gb!!!
E' proprio necessario?
Vogliamo vedere cosa succede "solo" con 50.000 righe (e non miliardi)?
set nocount on
set statistics io off
use tempdb
go
create table testPos
(
idRecord bigint primary key identity (1,1),
valore char(5)
)
go
create table testNeg
(
idRecord int primary key identity (-2147483648,1),
valore char(5)
)
go
declare @i int = 50000
while (@i > 0)
begin
insert testPos values ('a')
insert testNeg values ('a')
set @i -= 1
end
set statistics io on
select COUNT(1) from testPos
select COUNT(1) from testNeg
--> testPos: logical reads 138
--> testNeg: logical reads 114
--> 24 letture di differenza!
set statistics io off
;with cte as
(
select * from sys.dm_db_index_physical_stats(db_id(),
object_id('dbo.testPos'), NULL, NULL, 'DETAILED') where index_level = 0
union all
select * from sys.dm_db_index_physical_stats(db_id(),
object_id('dbo.testNeg'), NULL, NULL, 'DETAILED') where index_level = 0
)
select
object_name(object_id), index_depth, page_count, avg_record_size_in_bytes
from
cte
go
drop table testPos
drop table testNeg
go
Con 50.000 righe, utilizzando un BIGINT, ho 24 data pages in più, ovvero 24 * 8 Kb = 192 Kb buttati.