您正在查看: 标签 的时候 下的文章

索引访问方法接口定义索引唯一性检查

51.5. 索引唯一性检查

PostgreSQL使用唯一索引来强制SQL唯一约束,唯一 索引实际上是不允许多条记录有相同键值的的索引。一个支持这个特性的访问方法要 设置pg_am.amcanunique为真。目前,只有b-tree 支持它。

因为MvcC,必须允许重复的条目物理上存在于索引之中:该条目可能指向某个逻辑 行的后面的版本。实际想强制的行为是,任何 MvcC 快照都不能包含两条相同的索引 键字。这种要求在向一个唯一索引插入新行的时候分解成下面的几种情况:

  • 如果一个有冲突的合法行被当前事务删除,这是可以的。特别是因为一个 UPDATE总是在插入新版本之前删除旧版本,这样就允许一个行上的UPDATE不用改变键字进行操作。

  • 如果一个在等待提交的事务插入了一行有冲突的数据,那么准备插入数据的事 务必须等待看看改事务是否提交。如果该事务回滚,那么就没有冲突。如果它 没有删除冲突行然后提交,那么就有一个唯一性违例。实际上只是等待另外那 个事务结束,然后在程序里重做可视性检查。

  • 类似的,如果一个有冲突的有效行被一个准备提交的事务删除,那么另外一个 准备提交的插入事务必须等待该事务提交或者退出,然后重做测试。

此外,根据上面的规则进行唯一性检查之前,访问方法必须重新检查刚被插入的行是 否仍然"活跃",如果已经因为事务的提交而"钉死了",那么不应当发出任何错误。这 种情况不可能出现在插入同一个事务中创建的行的时候。但是在CREATE UNIQUE INDEX CONCURRENTLY的过程中是可能的。

要求索引访问方法自己进行这些测试,这就意味着它必须检查堆,以便查看那些根据 索引内容表明有重复键字的任意行的提交状态。这样做毫无疑问地很难看并且也不是 模块化的,但是这样可以节约重复的工作:如果进行额外的一次探测,而后面的索引 查找冲突行的的动作实际上是和查找插入新行的索引记录重复的动作。并且,没有很 显然的方法来避免冲突条件,除非冲突检查是插入新索引条目的整体动作的一部分。

如果唯一行性约束是可推迟的,这就更加复杂。我们需要能够向新行插入索引记录, 但推迟违反唯一性的错误直到声明的最后或者更迟的时候。为了避免对索引不必要 的重复搜索,索引访问方法应该在最初插入时做一次初步的唯一性检测。如果这个 结果表明记录里确定没有冲突了,就完成了。否则,我们会在该强制限制的时候安 排一个复核出现。(Note that for this purpose, "live" actually means "any tuple in the index entry's HOT chain is live".) To implement this, the aminsert function is passed a checkUnique parameter having one of the following values:

  • UNIQUE_CHECK_NO表明不需要做唯一性检测(这不是一个唯一 性索引)。

  • 正如上面所描述的,UNIQUE_CHECK_YES表明有一个不可延迟的唯 一性索引,并且必须立即做唯一性检测。

  • UNIQUE_CHECK_PARTIAL 表明唯一性约束是可延期的, PostgreSQL将会用这个模式方法来插入每一行 的索引记录。访问方法必须允许重复的记录进入索引,并且通过从 aminsert返回FALSE来报告任何可能的重复。对于返回FLASE的每一行,将 调度一个延迟的复核。

    访问方法必须能够识别任何可能违反唯一性约束的行,但是对他来说报告假 事实并不是错误。这样就允许检测不必等到其他是物流都结束了才做;冲突 报告在这里不会被当做错误来看待,并且随后将会被重新检测,到那个时候 它们可能不再是冲突了。

  • UNIQUE_CHECK_EXISTING表明这是一个行的延迟复核,这一行被报 告称之为一个潜在的唯一性违反。尽管这通过调用aminsert来执 行,在这种情况下这个访问方法绝不能插入一个新的索引记录。因为索引记录已有。 当然,访问方法必须检测以确认是否有另一个索引记录存在。如果是,并且如果 目标行也是仍然存在的,那么报告错误。

    我们推荐,在一个UNIQUE_CHECK_EXISTING调用中,访问方法进 一步查证在索引中的目标行实际上并没有一个现存的记录,并且如果不是这样 就报错。这是个好主意,因为被传到aminsert的索引元组值会 一直被验算。如果索引定义包含可变的函数,我们可能会检测索引的错误区域。 在复查中发现的行标签被用到原始的插入中。

系统表pg_pltemplate

45.31. pg_pltemplate

pg_pltemplate为过程语言存储"模板"信息。 一个语言的模板允许该语言可以在某个数据库里使用 简单的CREATE LANGUAGE命令创建,而不需要指定实现细节。

和许多系统表不一样,pg_pltemplate 是在集群里的所有数据库之间共享的: 每个集群只有一个pg_pltemplate的副本,而不是每个数据库一个。 这样就允许这些信息在需要时每个数据库都可以访问。

Table 45-31. pg_pltemplate Columns

名称类型描述
tmplnamename这个模板所应用的语言名
tmpltrustedboolean如果认为是可信的语言,则为真
tmpldbacreatebooleanTrue if language may be created by a database owner如果语言可能由一个数据库所有者创建,则为真
tmplhandlertext调用处理器函数名
tmplinlinetext匿名块处理函数名,如果没有,则null
tmplvalidatortext校验函数名,如果没有则为null
tmpllibrarytext实现语言的共享库的路径
tmplaclaclitem[]模板的访问权限(还未使用)

目前还没有任何命令可以用于操作过程语言模板;要修改内置的信息, 超级用户必须使用普通的INSERT,DELETE,UPDATE命令修改该表。 将来版本的PostgreSQL有可能提供一些命令来修改这些内容,以便更清晰些。

在实现的时候,tmplacl字段将提供对模板自身的访问控制(也就是使用它创建 一个语言的权限),而不是对那些从模板创建的语言的访问控制。

系统表pg_foreign_server

45.21. pg_foreign_server

目录 pg_foreign_server存储 外部服务器的定义。外部服务器描述为 连接到远程服务器,管理外部数据。外部 服务器通过外部数据包装访问。

Table 45-21. pg_foreign_server Columns

名称类型引用描述
srvnamename外服务器名
srvowneroidpg_authid.oid外服务器所有者
srvfdwoidpg_foreign_data_wrapper.oid外服务器的外数据包装的OID
srvtypetext服务器类型(可选)
srvversiontext服务器版本(可选)
srvaclaclitem[] 访问权限,请参阅 GRANT和 REVOKE获取详情
srvoptionstext[] 外服务器特定选项,如"keyword=value"字符串

系统表pg_foreign_data_wrapper

45.20. pg_foreign_data_wrapper

pg_foreign_data_wrapper表存储 外数据包装定义。外数据包装是通过访问外部数据,驻留在外部服务器的一种机制。

Table 45-20. pg_foreign_data_wrapper Columns

名称类型引用描述
fdwnamename外部数据包装名
fdwowneroidpg_authid.oid外数据包装所有者
fdwvalidatoroidpg_proc.oid 引用一个验证函数是负责 检查给予外部数据包通用选项的有效性 ,以及使用外部数据包的外服务器和用户 映射。如果没有验证提供,则为0。
fdwaclaclitem[] 访问权限,请参阅 GRANT和 REVOKE获取详情
fdwoptionstext[] 外数据包装特定选项,如"keyword=value"字符串

系统表pg_enum

45.19. pg_enum

pg_enum目录包含的条目 匹配枚举类型相关的值和标签。一个给定的枚举值的内部表示实际上是 在pg_enum中相关行的OID。 一个特定枚举类型的OID保证类型排序,但不能保证无关枚举类型OID的排序。

Table 45-19. pg_enum Columns

名称类型引用描述
enumtypidoidpg_type.oid pg_type项拥有此枚举值的OID
enumlabelname此枚举值的文本标签