函数索引把值在写入时预先算好
表达式索引把计算结果保存为索引键。查询比较 lower(email) 时,可以搜索预先计算的键,而不用对整张表逐行执行 lower。代价是索引创建和维护阶段需要完成计算与存储。它不会修改原始 email,也不保证任何查询都会选择这个索引,更不意味着表达式文本有一点不同就必然失去匹配。 预计算键把工作移到建索引和维护阶段;计算含义、唯一性规则与真实不可变性必须持续成立。 索引计算后的含义 lower(email) 索引保存的是与行关联的规范化结果,使用相同计算含义的等值条件可以成为索引条件。直接比较原始 email 的语义不同,不会自动获得这条搜索路径。同样,先 trim 再 lower 增加了一项操作,现有索引不能假定去除空白永远不会改变数据。因此是否匹配要看计算本身,而不是只看它们都涉及 email 列。 PostgreSQL 匹配解析后的表达式,并进行某些简化。多加几层括号本身不会破坏匹配,因此查询不需要与索引定义逐字完全相同。反过来,数学上等价的写法也不一定都能被识别为相同。应检查计划中的实际条件和索引表达式定义,不能只做表面字符串比较,也不能承诺规划器能够证明任意表达式等价。 唯一表达式索引还能执行大小写规范化后的唯一性规则。这是在改变允许存储的数据,不只是提速。已有行规范化后发生冲突,会阻止索引创建;未来插入也会面对新约束。单纯 lower 不是邮箱等价性的完整定义,其他文本还可能受 locale 和 collation 影响。应先明确业务规范化规则,再决定把哪一种计算结果作为约束依据。 让被索引的值保持稳定 索引表达式中的函数必须满足 PostgreSQL 的不可变性要求:结果应依赖输入参数,而不能随着当前时间或外部状态自行变化。now() 不能被当成永远稳定的计算值建索引。为了绕过检查而把函数随意标为 IMMUTABLE,并不会让函数真的不可变,反而可能使已存索引键与后续计算结果不一致,产生比慢查询更严重的正确性问题。 ...