PostgreSQL7.0手册-程序员手册 -40. 扩展的 SQL: 操作符
出了本章的范围,不过很幸运的是,通常你对自己的操作符只需要使用系统标准的计算器之一就行了。下面是一些标准限制计算器:
eqsel for =
neqsel for <>
scalarltsel for < or <=
scalargtsel for > or >=
这些都是分类,看起来有点奇怪,不过如果你仔细想想,就会觉得有道理。'=' 大多将只接受表中的一小部分行;'<>' 大多将拒绝一小部分行。'<' 将接受的行取决于给出的常量落在表的该列数据值的哪一个范围里(该值碰巧是 VACUUM ANALYZE 收集并且提供给选择性计算器的信息)。'<=' 在同样的常量时会接受比 '<' 略微大一些的行,不过它们也非常接近,几乎不值得区别开来,尤其是无论如何我们也比做盲猜好得多。类似的情况也适用于 '>' 和 '>='。
你可能常习惯于把 eqsel 或者 neqsel 用于那些非常高或者非常低选择性的操作符,即使它们并非真正相等或者不相等。例如,规则表达式匹配操作符(~,~*,等)常使用 eqsel,是基于这样的假设:它们只会匹配整个表中的一小部分记录。
你可以把 scalarltsel 和 scalargtsel 用于比较那些为进行范围比较被转化为数字尺度后有明显意义的数据类型。如果可能,把该数据类型增加到可以被文件 src/backend/utils/adt/selfuncs.c 里的过程 convert_to_scalar() 理解的部分。(最终,这个过程将被放到由 pg_type 表里的一个列标识的每种类型一个的函数代替,不过目前还没有这么做。)如果你没有做这些,系统仍然能工作,不过优化器的估计不会象想象的那么好。
在 src/backend/utils/adt/geo_selfuncs.c 里还有为几何操作符设计的额外的选择性函数:areasel,positionsel,和 contsel。在我写这些的时候,它们都只是存根,但是你还是可以使用(或者更好的是,改良它们)它们。
JOIN(联合)
如果提供了 JOIN 子句,则为操作符命名一个联合选择性函数(注意这里是函数名,不是操作符名)。JOIN 子句只是对返回布尔量的双目操作符有意义。一个联合选择性计算器后面的概念是猜测一对表上的那一部分行对目前的操作符将满足下面形式的 WHERE 子句的条件
table1.field1 OP table2.field2
和 RESTRICT 子句一样,这些很有可能帮助优化器用最少的处理勾画出要采取可能的联合顺序中的哪一个。
和前面一样,本节不会试图解释如何书写一个联合选择性计算器函数,但是会建议你在有一个可用的情况下,使用一个标准的计算器:
eqjoinsel for =
neqjoinsel for <>
scalarltjoinsel for < or <=
scalargtjoinsel for > or >=
areajoinsel for 2D area-based comparisons
positionjoinsel for 2D position-based comparisons
contjoinsel for 2D containment-based comparisons
HASHES
如果出现了 HASHES 子句,则告诉系统对于一个基于此操作符的联合可以使用哈希(散列)联合。HASHES 只对返回布尔量的双目操作符有意义,并且实际上该操作符最好是对某种数据类型的相等操作符。
哈希(散列)联合的假设是:对于一对哈希(散列)到同样的哈希(散列)代码的左和右操作数值,该联合操作符只能返回 TRUE。如果两个值被放到不同的哈希桶里,联合将根本不比较它们,隐含地意味着联合操作符的结果一定是 FALSE。所以对于不代表相等的操作符,声明 HASHES 是没有意义的。
实际上,逻辑相等还不够好;该操作符最好是代表完全的按位相等,因为哈希函数将对该值的内存表现形式进行计算而不管这些位的含义是什么。例如,时间间隔的相等不是按位相等;时间间隔相等操作符认为如果两个时间间隔具有相同持续时间时就是相等的,而不管它们的两个端点是否相等。这就意味着对于一个用 "=" 在时间间隔域之间的联合,如果用哈希联合实现将会和用别的联合实现生成不同的结果,因为可以匹配的大部分数据对将被哈希成不同的值因而不会被哈希联合进行比较。但是如果优化器选择使用不同的联合方法,所有等号操作符说相等的数据对都会被找出来。我们不想出现那种不一致性,所以我们没有标记时间间隔等号为可哈希的。
同时还有一些硬件相关的因素会导致一个哈希联合的计算错误。例如,如果你的数据类型是一个结构,结构里可能有不引人注意的填充位,这时把这个等号操作符标记为 HASHES 也是不安全的。(除非你书写你的其他操作符以确保这些未用的位总是零。)另一个例子是 FLOAT 数据类型对哈希联合也是不安全的。在符合 IEEE 浮点标准的机器上,负零和正零是不同的值(不同的位模式),但是它们被定义为比较相等。所以,如果浮点等号被标记为 HASHES,一个负零和一个正零可能不被哈希联合匹配,但是用其他联合处理,它们应该是匹配的。
底线是:你可能只能把 HASHES 用于用(或可能用) memcmp()实现的等号操作符。
SORT1 和 SORT2
如果出现了 SORT 子句,则告诉系统对基于目前的操作符可以使用融合联合方法。如果两者(左右数据类型)都是则都要声明。目前的操作符必须是对某一数据类型对的相等,并且 SORT1 和 SORT2 子句分别为左边和右边的数据类型命名了排序操作符('<' 操作符)。
融合联合是以这样的概念为基础的:对左边和右边的表进行排序,然后并行地扫描它们。所以,两种数据类型都必须是能够完全排序的,并且联合操作符必须只对那些落在排序顺序中的"某个位置"的数值对成功。实际上这意味着联合操作符必须表现得象等于。但是和哈希联合不同,(哈希联合里左边和右边的数据类型最好是相同的(至少是按位相等)),可以对两种不同数据类型进行融合联合 -- 只要他们逻辑相等即可。例如, int2 对 int4 的相等操作符是可以用融合联合的。我们只需要可以把两种数据类型排列成逻辑可比的序列的排序操作符即可。
当声明融合排序操作符时,目前的操作符和两个引用的操作符必须返回布尔变量;SORT1 操作符的两个输入数据类型必须和目前操
eqsel for =
neqsel for <>
scalarltsel for < or <=
scalargtsel for > or >=
这些都是分类,看起来有点奇怪,不过如果你仔细想想,就会觉得有道理。'=' 大多将只接受表中的一小部分行;'<>' 大多将拒绝一小部分行。'<' 将接受的行取决于给出的常量落在表的该列数据值的哪一个范围里(该值碰巧是 VACUUM ANALYZE 收集并且提供给选择性计算器的信息)。'<=' 在同样的常量时会接受比 '<' 略微大一些的行,不过它们也非常接近,几乎不值得区别开来,尤其是无论如何我们也比做盲猜好得多。类似的情况也适用于 '>' 和 '>='。
你可能常习惯于把 eqsel 或者 neqsel 用于那些非常高或者非常低选择性的操作符,即使它们并非真正相等或者不相等。例如,规则表达式匹配操作符(~,~*,等)常使用 eqsel,是基于这样的假设:它们只会匹配整个表中的一小部分记录。
你可以把 scalarltsel 和 scalargtsel 用于比较那些为进行范围比较被转化为数字尺度后有明显意义的数据类型。如果可能,把该数据类型增加到可以被文件 src/backend/utils/adt/selfuncs.c 里的过程 convert_to_scalar() 理解的部分。(最终,这个过程将被放到由 pg_type 表里的一个列标识的每种类型一个的函数代替,不过目前还没有这么做。)如果你没有做这些,系统仍然能工作,不过优化器的估计不会象想象的那么好。
在 src/backend/utils/adt/geo_selfuncs.c 里还有为几何操作符设计的额外的选择性函数:areasel,positionsel,和 contsel。在我写这些的时候,它们都只是存根,但是你还是可以使用(或者更好的是,改良它们)它们。
JOIN(联合)
如果提供了 JOIN 子句,则为操作符命名一个联合选择性函数(注意这里是函数名,不是操作符名)。JOIN 子句只是对返回布尔量的双目操作符有意义。一个联合选择性计算器后面的概念是猜测一对表上的那一部分行对目前的操作符将满足下面形式的 WHERE 子句的条件
table1.field1 OP table2.field2
和 RESTRICT 子句一样,这些很有可能帮助优化器用最少的处理勾画出要采取可能的联合顺序中的哪一个。
和前面一样,本节不会试图解释如何书写一个联合选择性计算器函数,但是会建议你在有一个可用的情况下,使用一个标准的计算器:
eqjoinsel for =
neqjoinsel for <>
scalarltjoinsel for < or <=
scalargtjoinsel for > or >=
areajoinsel for 2D area-based comparisons
positionjoinsel for 2D position-based comparisons
contjoinsel for 2D containment-based comparisons
HASHES
如果出现了 HASHES 子句,则告诉系统对于一个基于此操作符的联合可以使用哈希(散列)联合。HASHES 只对返回布尔量的双目操作符有意义,并且实际上该操作符最好是对某种数据类型的相等操作符。
哈希(散列)联合的假设是:对于一对哈希(散列)到同样的哈希(散列)代码的左和右操作数值,该联合操作符只能返回 TRUE。如果两个值被放到不同的哈希桶里,联合将根本不比较它们,隐含地意味着联合操作符的结果一定是 FALSE。所以对于不代表相等的操作符,声明 HASHES 是没有意义的。
实际上,逻辑相等还不够好;该操作符最好是代表完全的按位相等,因为哈希函数将对该值的内存表现形式进行计算而不管这些位的含义是什么。例如,时间间隔的相等不是按位相等;时间间隔相等操作符认为如果两个时间间隔具有相同持续时间时就是相等的,而不管它们的两个端点是否相等。这就意味着对于一个用 "=" 在时间间隔域之间的联合,如果用哈希联合实现将会和用别的联合实现生成不同的结果,因为可以匹配的大部分数据对将被哈希成不同的值因而不会被哈希联合进行比较。但是如果优化器选择使用不同的联合方法,所有等号操作符说相等的数据对都会被找出来。我们不想出现那种不一致性,所以我们没有标记时间间隔等号为可哈希的。
同时还有一些硬件相关的因素会导致一个哈希联合的计算错误。例如,如果你的数据类型是一个结构,结构里可能有不引人注意的填充位,这时把这个等号操作符标记为 HASHES 也是不安全的。(除非你书写你的其他操作符以确保这些未用的位总是零。)另一个例子是 FLOAT 数据类型对哈希联合也是不安全的。在符合 IEEE 浮点标准的机器上,负零和正零是不同的值(不同的位模式),但是它们被定义为比较相等。所以,如果浮点等号被标记为 HASHES,一个负零和一个正零可能不被哈希联合匹配,但是用其他联合处理,它们应该是匹配的。
底线是:你可能只能把 HASHES 用于用(或可能用) memcmp()实现的等号操作符。
SORT1 和 SORT2
如果出现了 SORT 子句,则告诉系统对基于目前的操作符可以使用融合联合方法。如果两者(左右数据类型)都是则都要声明。目前的操作符必须是对某一数据类型对的相等,并且 SORT1 和 SORT2 子句分别为左边和右边的数据类型命名了排序操作符('<' 操作符)。
融合联合是以这样的概念为基础的:对左边和右边的表进行排序,然后并行地扫描它们。所以,两种数据类型都必须是能够完全排序的,并且联合操作符必须只对那些落在排序顺序中的"某个位置"的数值对成功。实际上这意味着联合操作符必须表现得象等于。但是和哈希联合不同,(哈希联合里左边和右边的数据类型最好是相同的(至少是按位相等)),可以对两种不同数据类型进行融合联合 -- 只要他们逻辑相等即可。例如, int2 对 int4 的相等操作符是可以用融合联合的。我们只需要可以把两种数据类型排列成逻辑可比的序列的排序操作符即可。
当声明融合排序操作符时,目前的操作符和两个引用的操作符必须返回布尔变量;SORT1 操作符的两个输入数据类型必须和目前操

