news 2026/10/29 10:01:11

PostgreSQL 整数类型全解析:smallint、integer、bigint 的字节、取值范围与类型推断

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PostgreSQL 整数类型全解析:smallint、integer、bigint 的字节、取值范围与类型推断
  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

PostgreSQL 内置了三种尺寸的整数类型——smallint(int2)、integer(int4)与bigint(int8),它们分别占用 2、4、8 个字节,且全部为有符号整数。本文以本仓库的 integers-in-postgres.md 为主线,系统梳理三种整数类型的存储大小、精确取值范围、字面量的自动类型推断规则,并结合仓库中 postgres-does-not-support-unsigned-integers.md、checking-the-type-of-a-value.md 等关联笔记,深入讲解pg_typeof调试技巧、无符号整数缺失的替代方案以及建表与迁移中的最佳实践。读完你将能准确选择整数列类型、解释pg_typeof的推断结果,并规避整数溢出与类型变更陷阱。

三种整数类型:同族同源,尺寸不同

PostgreSQL 的整数家族没有"种类"之分,只有"尺寸"之别。官方名称分别是:

类型名别名占用字节位宽取值范围
smallintint22 字节16 位-32768 ~ +32767
integerint44 字节32 位-2147483648 ~ +2147483647
bigintint88 字节64 位-9223372036854775808 ~ +9223372036854775807

三者都只能表示有符号整数。以 4 字节的integer为例,32 位二进制能表示的取值范围是 -2147483648 到 +2147483647,即全部 4 字节所能容纳的数值;同理,2 字节的smallint覆盖 -32768 到 +32767,8 字节的bigint覆盖 -9223372036854775808 到 +9223372036854775807。

值得注意的是,别名int2、int4、int8并不仅是文档里的简称,它们在系统目录pg_type中就是真实存在的类型名。仓库笔记 types-by-category.md 演示了如何通过数值类型的类别代码N枚举全部数值类型:

select typname from pg_type where typcategory = 'N'; typname ----------------- int8 int2 int4 regproc oid float4 float8 money numeric ... (17 rows)

可以看到int8、int2、int4正是pg_type目录中的正式类型名,smallint、integer、bigint只是面向用户的 SQL 别名。

用 pg_typeof 观察字面量的自动推断

正如 integers-in-postgres.md 所强调的:虽然列可以被显式限制为特定尺寸的整数,但 PostgreSQL 在"即席"处理整数(即 SQL 字面量、表达式中间值)时足够聪明,默认使用integer,仅在必要时才升级为bigint。

这一点可以用pg_typeof()函数直接验证。pg_typeof()返回任意表达式在 PostgreSQL 中的实际数据类型,是排查类型推断问题最直接的工具(详见仓库笔记 checking-the-type-of-a-value.md):

> select pg_typeof(55); pg_typeof ----------- integer > select pg_typeof(99999999999999999); pg_typeof ----------- bigint

字面量55落在integer的范围内,于是被推断为integer(int4);而99999999999999999(约 10^17)明显超出 32 位有符号整数上限 2147483647,PostgreSQL 自动将其推断为bigint(int8)。这正是"默认integer,必要时才bigint"这一策略的直观体现——字面量的推断完全由数值大小驱动。

pg_typeof还能揭示一些细微行为。例如对一个字符串字面量调用它,PostgreSQL 暂时无法判定该用text还是varchar,会返回unknown:

> select pg_typeof('hello'); pg_typeof ----------- unknown

此时只需显式标注目标类型即可得到确定结果:

> select pg_typeof('hello'::varchar); pg_typeof ------------------- character varying

同理,如果你想强制一个超出integer范围的数值在计算中被当作smallint(尽管会溢出),或用显式类型让字面量按预期宽度参与运算,都可以借助::int2、::int4、::int8这类类型转换语法。

没有无符号整数:范围限制与替代方案

由于三种整数类型全部是有符号的,PostgreSQL 并不提供 MySQL 那样的UNSIGNED修饰符。仓库笔记 postgres-does-not-support-unsigned-integers.md 专门讨论了这一点:

以integer为例,我们只能存储 -2147483648 到 +2147483647 之间的数值——这是 4 字节所能容纳的全部。若系统支持 4 字节无符号整数,理论上可以从 0 一直表示到 4294967295。

这意味着如果你原本指望"数据类型本身"来强制某列数据非负(比如商品数量、访问计数),在 PostgreSQL 中必须另想办法。该笔记给出了两个常见方案:

  1. CHECK 约束:直接为列添加非负校验,例如
    create table inventory ( quantity integer check (quantity > 0) );
  2. 自定义 DOMAIN 类型:创建一个限制合法取值的用户定义域类型,例如
    create domain non_negative_int as integer check (value >= 0);

    不过该笔记作者的评价是:"使用域类型的交互方式有些笨拙,不值得为此投入精力。"

需要特别提醒的是,无论 CHECK 约束还是 DOMAIN 类型,都只是近似模拟无符号整数——它们并没有真正扩大取值范围。也就是说,即使加上check (value >= 0),integer列的最大值依然是 2147483647,而不是无符号版的 4294967295。如果你的业务数据可能超过有符号上限,正确做法是直接选用更大的整数类型(如bigint),而不是靠约束"挤"出高位。

建表实践:主键与常用整数列

理解三种整数类型的字节与范围后,建表时的选择就清晰了。仓库笔记 create-a-composite-primary-key.md 展示了整数作为外键与主键组成部分的典型用法:

create table plane_tickets ( passenger_id integer references passengers not null, flight_id integer references flights not null, confirmation_number varchar(6) not null, seat_assignment varchar not null, primary key (passenger_id, flight_id) );

这里的外键列都使用了默认的integer——对于绝大多数业务主键(数据量在 21 亿以内)它完全够用,而且 4 字节比bigint的 8 字节在存储和索引上更省空间。

至于自增主键,仓库笔记 generate-modern-primary-key-columns.md 给出了一条重要建议:serial/bigserial已经过时,PostgreSQL 官方 wiki 明确 "Don't use serial",新应用应优先使用 identity 列。它对比了两种写法:

传统serial写法(不推荐):

create table books ( id serial primary key, title text not null, author text not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now() );

现代 identity 列写法(推荐):

create table books ( id int primary key generated always as identity, title text not null, author text not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now() );

如果预计行数会超过 21 亿,则应把主键列换成bigint(或bigint generated always as identity)。

类型迁移:从 int 到 bigint 何时需要 USING

当业务规模增长、integer不再够用时,常见操作是把列升级为bigint。仓库笔记 switch-non-castable-column-type-with-using-clause.md 指出:从int到bigint属于可以自动类型转换(cast)的变更,PostgreSQL 知道如何原地转换现有数据,因此可以直接执行:

alter table users alter column id set data type bigint;

之所以不需要using子句,是因为整数类型之间的加宽转换(int2→int4→int8)是无损且内建的,PostgreSQL 能自动完成。与之对比,int到uuid这类不存在内建转换路径的变更,就必须显式提供using子句告诉数据库如何生成新值:

alter table users alter column id set data type uuid using (gen_random_uuid());

因此,当你规划"把id从int扩成bigint"这样的迁移时,可以直接使用上面的alter column ... set data type语句,PostgreSQL 会负责把既有数据的类型安全地加宽。

小结与选型建议

围绕本仓库 integers-in-postgres.md 的核心内容,可以总结出以下要点:

  • PostgreSQL 只有三种尺寸的整数:smallint(2 字节,±32767)、integer(4 字节,±2147483647)、bigint(8 字节,±9223372036854775807),别名分别为int2、int4、int8;
  • 三者均为有符号整数,PostgreSQL不支持无符号整数,非负约束需用 CHECK 约束或 DOMAIN 类型近似实现,且无法扩大取值范围;
  • 在即席表达式(字面量)中,PostgreSQL 默认推断为integer,超出其范围才升级为bigint,可用pg_typeof()验证;
  • 建表选型时,常规主键与计数用integer即可;高容量场景选用bigint;新应用主键优先使用generated always as identity而非serial;
  • int→bigint属于自动可转换的类型变更,可直接通过alter column ... set data type完成,无需using子句。

掌握了这些字节与范围知识,你就能在设计表结构时做出精准取舍,也能在面对pg_typeof的输出、溢出告警或类型迁移需求时快速定位问题。

  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

相关推荐

上一篇:终极小米运动自动刷步数完整指南:轻松实现微信支付宝步数同步
下一篇:如何快速掌握OpenRPA:企业级自动化工具的完整实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 0:54:37

上下文模式:分布式系统稳定性与超时控制的实践指南

后端开发和系统架构里,有个东西平时不显山不露水,但几乎每一个线上接口、每一段异步任务、每一次RPC调用背后都有它的影子,这就是context-mode,上下文模式。说白了,它解决的是这么一个问题:一次用户请求从网…

作者头像 李华
网站建设 2026/10/15 18:11:51

Calibre 格式转换完整指南:EPUB 进 Kindle 只要两分钟

Calibre 格式转换完整指南:EPUB 进 Kindle 只要两分钟 【免费下载链接】calibre The official source code repository for the calibre ebook manager 项目地址: https://gitcode.com/GitHub_Trending/ca/calibre EPUB 直接丢给 Kindle,它会提示…

作者头像 李华
网站建设 2026/10/29 1:32:49

AI技能插件实战:打造Ponytail马尾辫造型决策工具

提到 ponytail,很多人第一反应就是“马尾辫嘛,谁不会扎”。但真正上手之后你会发现,远不是那回事——同一个马尾,扎高一点、低一点、松一点、紧一点,视觉效果天差地别。我前后折腾了大半年,试过无数教程&am…

作者头像 李华
网站建设 2026/10/17 5:53:41

Halide 调度入门:算法与调度分离的编程模型与三个性能杠杆

编译器图像处理编程语言高性能计算 【免费下载链接】Halide a language for fast, portable data-parallel computation 项目地址: https://gitcode.com/gh_mirrors/ha/Halide 点击查看 免费下载 Halide 是一门面向快速、可移植数据并行计算的语言,它的…

作者头像 李华
网站建设 2026/10/17 11:49:31

C++随机数生成的五种方法

C/C 随机数生成方法1. 使用 rand() 和 srand()库: <stdlib.h> 或 <cstdlib>特点: 伪随机数生成器&#xff0c;简单易用。示例:123456789#include <stdlib.h>#include <time.h>int main() {srand(time(NULL)); // 初始化随机数生成器int random_number…

作者头像 李华