pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
索引通常用于增强数据库性能。应该把索引定义在重复查询中用作限定条件的表列(或类属性)上。不当使用会导致性能变慢,因为在有索引的情况下,更新和插入的时间会增加。
索引也可以用来强制表的主键唯一。当索引被声明为 UNIQUE 时,将不允许存在多个具有相同索引项的表行。出于这种目的时,目标是确保数据一致性而不是改善性能,因此上面关于不当使用的告诫并不适用。
可以定义两种形式的索引:
对于值索引,索引的键字段用列名指定;如果索引访问方法支持多列索引,可以指定多个列。
对于函数索引,索引定义在一个函数应用于单个类的一个或多个属性所得的结果上。即使函数使用多个输入字段,这也是一个单列索引(即函数结果)。函数索引可用于基于某些操作符快速访问数据,这些操作符通常需要经过某种变换才能应用到基础数据上。
Postgres 为索引提供了 btree、rtree 和 hash 访问方法。btree 访问方法是 Lehman-Yao 高并发 btree 的一种实现。rtree 访问方法使用 Guttman 的二次分裂算法实现标准 rtree。hash 访问方法是 Litwin 线性散列的一种实现。我们提到这些算法只是为了说明所有这些访问方法都是完全动态的,不需要定期优化(例如,与静态散列访问方法的情况不同)。
只要被索引属性参与的比较使用下列操作符之一,Postgres 查询优化器就会考虑使用 btree 索引: <, <=, =, >=, >
只要被索引属性参与的比较使用下列操作符之一,Postgres 查询优化器就会考虑使用 rtree 索引: <<, &<, &>, >>, @, ~=, &&
只要被索引属性参与的比较使用 = 操作符,Postgres 查询优化器就会考虑使用 hash 索引。
当前,只有 btree 访问方法支持多列索引。默认最多可以指定 16 个键(在构建 Postgres 时可以改变这个限制)。
可以为索引的每一列指定一个操作符类。操作符类确定索引针对该列使用哪些操作符。例如,建立在四字节整数上的 btree 索引会使用int4_ops类;该操作符类包含针对四字节整数的比较函数。实际中,字段的默认操作符类通常就足够了。之所以需要操作符类,主要是因为对于某些数据类型,可能存在不止一种有意义的排序方式。例如,可能希望按绝对值或实部对复数数据类型排序。可以为该数据类型定义两个操作符类,并在创建索引时选择合适的类。此外还有一些特殊用途的操作符类:
操作符类box_ops和bigbox_ops都支持box数据类型上的 rtree 索引。它们的区别在于,bigbox_ops会将框的坐标按比例缩小,以避免在对非常大的浮点坐标做乘法、加法和减法时出现浮点异常。如果你的矩形所在的范围大约在 20,000 个单位见方或更大,就应该使用bigbox_ops。
int24_ops操作符类用于在 int2 数据上构建索引,并在查询限定条件中与 int4 数据进行比较。类似地,int42_ops支持在 int4 数据上构建索引,以便在查询中与 int2 数据进行比较。
下面的查询会显示所有已定义的操作符类:
SELECT am.amname AS acc_name,
opc.opcname AS ops_name,
opr.oprname AS ops_comp
FROM pg_am am, pg_amop amop,
pg_opclass opc, pg_operator opr
WHERE amop.amopid = am.oid AND
amop.amopclaid = opc.oid AND
amop.amopopr = opr.oid
ORDER BY acc_name, ops_name, ops_comp
使用 DROP INDEX 来删除索引。
由 Herouth Maoz 撰写。它最初于 1998-03-02 发表在用户邮件列表上,作为对问题 “What is the difference between PRIMARY KEY and UNIQUE constraints?”的回答。
Subject: Re: [QUESTIONS] PRIMARY KEY | UNIQUE
下面两者有什么区别:
PRIMARY KEY(fields,...) 和
UNIQUE (fields,...)
- 这是一个别名吗?
- 如果 PRIMARY KEY 已经是唯一的,那为什么
还会有另一种名为 UNIQUE 的键?
主键是用来标识特定行的字段。例如,用社会保障号码标识一个人。
一个单纯的 UNIQUE 字段组合与标识行无关,它只是一种完整性约束。例如,我有若干链接集合。每个集合由一个唯一的编号标识,这个编号就是主键。这个键用于关系。
不过,我的应用还要求每个集合有一个唯一的名称。为什么?为了让想要修改集合的人能够识别它。如果你有两个名为"Life Science"的集合,就很难知道究竟标记为 24433 的那个才是你需要的,而标记为 29882 的那个不是。
因此,用户通过名称来选择集合。我们因而在数据库中确保名称是唯一的。但是,数据库中没有其他表通过集合名称与 collections 表关联,那样做会非常低效。
而且,集合名称尽管唯一,实际上并不定义这个集合!例如,如果有人决定把集合的名称从"Life Science"改为"Biology",它仍然是同一个集合,只是名称不同而已。只要名称是唯一的,这就没有问题。
所以:
主键:
用于标识行并与其他数据相关联。
不可能(或很难)更新。
不应允许 NULL。
唯一字段:
用作访问行的另一种途径。
可以更新,只要保持唯一。
可以接受 NULL。
至于为什么标准 SQL 语法中没有显式定义非唯一键?你必须理解,索引是依赖于实现的。SQL 不定义实现,只定义数据库中数据之间的关系。Postgres 确实允许非唯一索引,但用于强制 SQL 键的索引总是唯一的。
因此,你可以按列的任意组合查询一个表,即使你在这些列上并没有索引。索引只是每种 RDBMS 提供给你的实现辅助手段,目的是让常用的查询执行得更高效。有些 RDBMS 还可能提供额外的手段,例如把键保存在主存中。它们会有一个特殊命令,例如
CREATE MEMSTORE ON <table> COLUMNS <cols>
(这不是一个真实存在的命令,只是一个例子。)
事实上,当你创建主键或唯一的字段组合时,SQL 规范中没有任何地方说会创建索引,也没有说按键检索数据会比顺序扫描更高效!
所以,如果你想用一个不唯一的字段组合作为辅助键,其实完全不必指定任何东西——直接按那个组合开始检索就行了!不过,如果你想让检索高效,就得求助于你的 RDBMS 供应商提供的手段——无论是索引、我虚构的 MEMSTORE 命令,还是一个智能的 RDBMS:它会根据你曾基于特定键组合发送过许多查询这一事实,在你不知情的情况下创建索引……(它从经验中学习)。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。