PRIMARY KEY 实际上意味着什么?我的表是否需要一个?

Ale*_*nch 3 sql database postgresql database-schema postgresql-9.3

我有一个 PostgreSQL 9.3 数据库,其中有一个用户表,该表以保留大小写的格式存储用户名。所有查询都不区分大小写,因此我应该有一个支持它的索引。此外,无论大小写,用户名都必须是唯一的。

这就是我想出的:

forum=> \d users
                      Table "public.users"
   Column   |           Type           |       Modifiers
------------+--------------------------+------------------------
 name       | character varying(24)    | not null
Indexes:
    "users_lower_idx" UNIQUE, btree (lower(name::text))
Run Code Online (Sandbox Code Playgroud)

用标准 SQL 语法表示:

CREATE TABLE users (
    name varchar(24) NOT NULL
);
CREATE UNIQUE INDEX "users_lower_idx" ON users (lower(name));
Run Code Online (Sandbox Code Playgroud)

通过这个模式,我已经满足了所有的约束,尽管没有主键。SQL 标准不支持功能主键,因此我无法提升索引:

forum=> ALTER TABLE users ADD PRIMARY KEY USING INDEX users_lower_idx;
ERROR:  index "users_lower_idx" contains expressions
LINE 1: ALTER TABLE users ADD PRIMARY KEY USING INDEX users_lower_id...
                              ^
DETAIL:  Cannot create a primary key or unique constraint using such an index.
Run Code Online (Sandbox Code Playgroud)

但是,我已经有了 UNIQUE 约束,并且该列已经标记为“NOT NULL”。如果我必须有一个主键,我可以像这样构造表:

CREATE TABLE users (
    name varchar(24) PRIMARY KEY
);
CREATE UNIQUE INDEX "users_lower_idx" ON users (lower(name));
Run Code Online (Sandbox Code Playgroud)

但这样我就会有两个索引,这对我来说似乎很浪费而且没有必要。那么,PRIMARY KEY 对 postgres 来说除了“UNIQUE NOT NULL”之外还有什么特别的意义吗?我是否因为没有 PRIMARY KEY 而错过了什么?

Erw*_*ter 5

首先,几乎每个表都应该有一个主键。

citext

附加模块提供同名的数据类型。“ci”不区分大小写。根据文档:

citext模块提供了不区分大小写的字符串类型, citext. 本质上,它lower在比较值时在内部调用。否则,它的行为几乎与 完全相同text

它的目的正是您所描述的目的:

citext数据类型允许您消除 SQL 查询中对 lower 的调用,并允许主键不区分大小写

大胆强调我的。
请务必先阅读有关限制的手册。每个数据库安装一次

CREATE EXTENSION citext;
Run Code Online (Sandbox Code Playgroud)

text

如果您不想走这条路,我建议您添加一个serial作为代理主键

CREATE TABLE users (
    user_id serial PRIMARY KEY
  , username text  NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

我会用text而不是varchar(24). CHECK如果需要强制执行最大长度(稍后可能会更改),请使用约束。细节:

以及UNIQUE原始设计中的索引(没有类型转换):

CREATE UNIQUE INDEX users_username_lower_idx ON users (lower(username));
Run Code Online (Sandbox Code Playgroud)

integera 的底层serial小而快,不必浪费时间lower()或数据库的排序规则。这对于外键引用特别有用。我更喜欢它而不是一些具有不同属性的自然主键。

两种解决方案都有优点和缺点。