当前位置:首页 > 技术知识 > 正文内容

第 16 章:数据类型进阶 - PostgreSQL入门

maynowei11个月前 (08-07)技术知识115

在第 4 章,我们已经学习了像 INT, VARCHAR, DATE 这样的基本数据类型。它们就像是工具箱里的螺丝刀和扳手,能解决大部分日常问题。


但是,PostgreSQL 之所以强大,很大程度上因为它提供了一个极其丰富的“军火库”,里面有各种为特定场景量身打造的高级数据类型。用好它们,能极大地提升数据存储的效率、安全性和查询的便利性。

这一章,我们就来认识几位重量级选手:

  • SERIAL: 实现自动增长的整数 ID。
  • UUID: 全局唯一标识符,应对分布式系统的挑战。
  • ARRAY: 在一个字段里存储多个值。
  • JSON/JSONB: 在关系型数据库中优雅地处理半结构化数据。
  • TIMESTAMPTZ: 带时区的时间戳,解决全球化应用的时间问题。

16.1SERIAL和BIGSERIAL:自增主键

在之前的例子中,我们为 id 列手动插入 1, 2, 3... 这样的值。这很麻烦,而且在多用户同时插入时,很容易产生冲突。

SERIAL 类型就是为了解决这个问题而生的。它并不是一个真正的数据类型,而是一个“语法糖”,一个快捷方式。

当你将一列定义为 SERIAL 时,PostgreSQL 会自动为你做三件事:

  1. 创建一个序列 (Sequence) 对象,这是一个专门用来生成不重复数字的计数器。
  2. 将列的数据类型设置为 INTEGER
  3. 将列的默认值设置为从上面那个序列中获取下一个值。

使用方法:

CREATE TABLE products (
    product_id SERIAL PRIMARY KEY, -- 看这里!
    product_name VARCHAR(100) NOT NULL
);

现在,当我们插入数据时,完全不需要product_id 提供值,数据库会自动为我们生成!

INSERT INTO products (product_name) VALUES ('笔记本电脑');
INSERT INTO products (product_name) VALUES ('机械键盘');

SELECT * FROM products;

执行结果:

 product_id | product_name
------------+--------------
          1 | 笔记本电脑
          2 | 机械键盘
(2 rows)

product_id 被自动、安全地赋予了 1 和 2。

  • SERIAL: 对应 INTEGER,最大值约 21 亿。对于绝大多数应用都够用了。
  • BIGSERIAL: 对应 BIGINT,最大值约 9 百京(9 x 10^18)。如果你的表可能会有天文数字级别的行数(比如日志、事件记录),请使用 BIGSERIAL

16.2UUID数据类型

SERIAL 生成的 ID 在单台数据库内是唯一的,但如果你的系统是分布式的,有多台数据库都需要生成 ID,SERIAL 就可能产生冲突。

UUID (Universally Unique Identifier) 就是为解决这个问题而生的。它是一个 128 位的数字,通常表示为 32 个十六进制数的字符串,比如
550e8400-e29b-41d4-a716-446655440000

UUID 的值是通过算法生成的,它能保证在全世界的范围内,你生成的每一个 UUID 都是几乎不可能重复的。

使用方法:
首先,我们需要启用一个内置的扩展
uuid-ossp,它提供了生成 UUID 的函数。

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

然后,在建表时使用 UUID 类型,并设置默认值为 uuid_generate_v4() (生成版本 4 的随机 UUID)。

CREATE TABLE documents (
    doc_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    title TEXT
);

INSERT INTO documents (title) VALUES ('第一份机密文件');
INSERT INTO documents (title) VALUES ('第二份机密文件');

SELECT * FROM documents;

执行结果:

               doc_id               |      title
------------------------------------+--------------------
 a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d | 第一份机密文件
 b6c7d8e9-f0a1-4b2c-8d9e-1f2a3b4c5d6e | 第二份机密文件
(2 rows)

doc_id 被赋予了全局唯一的、无规律的 ID。


16.3ARRAY数组类型

有时候,我们需要在一个字段里存储一组同类型的值,比如一篇文章的多个标签、一个用户的多个电话号码。

传统做法是再建一张关联表(比如 post_tags 表),但这对于简单的场景来说有点“杀鸡用牛刀”。PostgreSQL 的 ARRAY 类型提供了一个更直接的解决方案。

你可以创建任何基础数据类型的数组,比如 INTEGER[], TEXT[], DATE[]

使用方法:

CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    title TEXT,
    tags TEXT[] -- 文本类型的数组
);

INSERT INTO articles (title, tags)
VALUES ('学习SQL', '{"sql", "database", "postgres"}');

INSERT INTO articles (title, tags)
VALUES ('学习Python', ARRAY['python', 'programming']); -- 另一种语法

SELECT * FROM articles;
  • 数组的值可以用 {} 大括号括起来的字符串表示,也可以用 ARRAY[...] 语法。

查询数组:
PostgreSQL 提供了一系列强大的函数和操作符来查询数组。

-- 找出所有包含 'sql' 标签的文章
SELECT title FROM articles WHERE 'sql' = ANY(tags);

-- 找出所有同时包含 'python' 和 'programming' 标签的文章
SELECT title FROM articles WHERE tags @> ARRAY['python', 'programming'];

16.4JSON和JSONB:处理半结构化数据

这可能是 PostgreSQL 最强大的特性之一。它允许你在关系型数据库中,原生、高效地存储和查询 JSON 数据。

  • JSON: 以纯文本形式存储 JSON 数据。它会检查 JSON 格式是否合法,但仅此而已。
  • JSONB: 以二进制格式存储 JSON 数据。它在存入时会做一些预处理,比如去掉重复的键、排序键等。

JSON vs JSONB:

特性

JSON

JSONB

存储

纯文本,保留原始格式(空格、顺序、重复键)

二进制,不保留格式,效率更高

写入速度

(因为只做格式检查)

稍慢 (因为要解析和转换)

查询速度

(每次查询都要重新解析)

极快 (因为可以被索引)

索引支持

有限

非常强大 (支持 GIN 索引)

黄金法则 :除非你有特殊需求要保留 JSON 的原始文本格式,否则永远优先使用 JSONB

使用方法:

CREATE TABLE user_profiles (
    user_id INT PRIMARY KEY,
    profile JSONB
);

INSERT INTO user_profiles (user_id, profile) VALUES
(1, '{
    "name": "张三",
    "contact": {
        "email": "zhangsan@example.com",
        "phones": ["138...", "139..."]
    },
    "interests": ["reading", "coding"]
}');

-- 查询 JSON 内部的字段
-- -> 操作符返回一个 JSON 对象,->> 操作符返回文本
SELECT
    profile -> 'name' AS json_name, -- 返回 "张三" (带引号的JSON字符串)
    profile ->> 'name' AS text_name, -- 返回 张三 (纯文本)
    profile -> 'contact' ->> 'email' AS email -- 链式查询
FROM user_profiles
WHERE user_id = 1;

-- 查询 JSON 数组中的元素
SELECT profile -> 'interests' -> 0 FROM user_profiles; -- 返回 "reading"

-- 检查是否存在某个键
SELECT * FROM user_profiles WHERE profile ? 'name';

16.5TIMESTAMPvsTIMESTAMPTZ(带时区)

  • TIMESTAMP: TIMESTAMP WITHOUT TIME ZONE 的别名。它只记录日期和时间,比如 2023-10-27 10:00:00。它不包含任何时区信息。
  • TIMESTAMPTZ: TIMESTAMP WITH TIME ZONE 的别名。这是 PostgreSQL 中处理时间最推荐的方式。

TIMESTAMPTZ 的工作方式非常聪明:

  1. 当你插入一个时间值时,它会根据你当前数据库会话的时区设置,将这个时间转换成 UTC (协调世界时) 进行存储。
  2. 当你查询这个值时,它又会根据你当前会话的时区设置,将存储的 UTC 时间转换回你本地的时区时间来显示。

这意味着,无论你的用户和服务器在世界哪个角落,TIMESTAMPTZ 存储的都是一个绝对的、无歧义的时间点

黄金法则 :只要你的应用需要处理不同时区的用户,或者服务器可能部署在不同时区,请始终使用 TIMESTAMPTZ


本章小结

你已经为你的数据表装备上了一批精良的“特种武器”!

  • 我们学会了用 SERIAL 来创建自增主键
  • UUID 来应对分布式系统的唯一 ID 需求。
  • ARRAY 来方便地存储数组
  • 用强大的 JSONB 来拥抱半结构化数据
  • TIMESTAMPTZ 来一劳永逸地解决时区问题。

为你的数据选择最合适的数据类型,是数据库设计的核心一环。一个好的设计,能让你的应用事半功倍。

从下一章开始,我们将进入第四部分:数据完整性与表设计。我们将学习如何通过各种“约束”来保证数据的质量和一致性,这是构建一个健壮、可靠的数据库系统的基石。我们下一章见!

相关文章

Objective C interface(objective什么意思)

在Objective C里面,interface基本可以理解为其他语言里面的class。当然也有些不同。首先我们可以新建一个Objective-C的file。这里我们添加一个MyClass.m和一个M...

Oracle数据库云服务系列新增前所未有的企业级功能

新推出的关键任务型功能包括:实现容错可用性和按需可扩展性的集群;零数据丢失灾难恢复;Oracle数据库Exadata云服务。甲骨文还宣布推出一项最新免费数据库云服务,数据库管理员和开发人员通过该服务可...

Oracle数据库安装 | 步骤详细(oracle数据库怎么安装及配置)

部署环境系统:CentOS 7.1 (Redhat版本也可以)数据库:Oracle 11gR2 1.修改hosts文件1.1 查询主机名和IP地址1.2 修改/etc/hosts文件如下2.挂载操作系...

每天学Java!Java Bean是什么概念(java bean有什么用)

对于初学Java,或者是刚接触J2EE的人来说,Java bean确实是一个不太好理解的概念,对于一些专业的解释呢,好像看起来也不是那么容易理解。所以小华君今天就准备跟大家说一说Java bean的概...

China to work with all member states to complete preparations in final phase for SCO Tianjin summit: spokesperson

BEIJING, July 31 (Xinhua) -- China will work with all the Shanghai Cooperation Organization (SCO) me...

Amundi sees "US Exceptionalism" eroding, while turns bullish on China's AI

南方财经全媒体记者 袁思杰 孙迟悦 香港报道"The support for US exceptionalism has weakened since the beginning of this ye...