【问题标题】:PostgreSQL: Create index on length of all table fieldsPostgreSQL:在所有表字段的长度上创建索引
【发布时间】:2016-03-12 14:51:39
【问题描述】:

我有一张名为profile 的表,我想按哪些表填写最多。每个列都是 JSONB 列或 TEXT 列。我在很大程度上不需要这个,所以我通常按以下顺序订购:

SELECT * FROM profile ORDER BY LENGTH(CONCAT(profile.*)) DESC;

但是,这很慢,所以我想创建一个索引。但是,这不起作用:

CREATE INDEX index_name ON profile (LENGTH(CONCAT(*))

也没有

CREATE INDEX index_name ON profile (LENGTH(CONCAT(CAST(* AS TEXT))))

不能说我很惊讶。声明这个索引的正确方法是什么?

【问题讨论】:

  • “不起作用”是对问题的错误描述。

标签: performance postgresql database-performance database-indexes


【解决方案1】:

要在文本表示中测量行的大小,您可以将整行转换为文本,这比连接单个列要快得多:

SELECT length(profile::text) FROM profile;

但是索引中的这个表达式有 3 个(或 4 个)问题:

  1. CREATE INDEX 不接受语法简写profile::text,您需要添加额外的括号或默认为标准语法cast(profile AS text)

  2. 仍然存在与@jjanes already discussed 相同的问题:索引表达式中只允许使用IMMUTABLE 函数,并且将行类型转换为text 不会满足此要求。您可以构建一个伪造的 IMMUTABLE 包装函数,就像 Jeff 概述的那样。

  3. 存在固有的歧义(这也适用于 Jeff 的回答!):如果您的列名与表名相同(这是一种常见情况),您无法引用 CREATE INDEX 中的行类型,因为标识符总是首先解析为列名。

  4. 与原始文件的细微差别:这会将列分隔符、行装饰符和可能的转义字符添加到 text 表示中。对您的用例应该没有太大影响。

但是,我建议使用更激进的替代方案作为行大小的粗略指标:pg_column_size()。更短更快,避免问题134

SELECT pg_column_size(profile) FROM profile;

问题 2 仍然存在:pg_column_size() 也只是 STABLE。您可以创建一个简单而廉价的 SQL 包装函数:

CREATE OR REPLACE FUNCTION pg_column_size(profile)
  RETURNS int LANGUAGE sql IMMUTABLE AS
'SELECT pg_catalog.pg_column_size($1)';

然后像@jjanes 概述的那样继续。更多详情:

请注意,我使用行类型profile 作为参数创建了函数。 Postgres 允许函数重载,这就是为什么我们可以使用相同的函数名。现在,当我们将匹配的行类型提供给 pg_column_size() 时,我们的自定义函数根据 function type resolution 规则匹配得更紧密,并且被选择而不是多态系统函数。或者,使用单独的名称,并可能使函数多态......

相关:

【讨论】:

    【解决方案2】:

    您可以声明一个被错误标记为“不可变”的函数并在其上建立索引。

    CREATE OR REPLACE FUNCTION len_immut(record)
     RETURNS int
     LANGUAGE plperl
     IMMUTABLE
    AS $function$
      ## This function lies about its immutability.
      ## Use it with care.  It is useful for indexing
      ## entire table rows.
      return length(join ",", values %{$_[0]});
    $function$
    

    然后

    create index on profile (len_immut(profile));
    
    SELECT * FROM profile ORDER BY len_immut(profile) DESC;
    

    由于该函数被错误地标记为immutable,因此如果您在表上添加或删除列或更改列类型等操作,索引可能会过期。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-06
      • 2021-08-20
      • 1970-01-01
      • 2018-01-18
      • 1970-01-01
      • 1970-01-01
      • 2019-11-12
      • 2017-06-14
      相关资源
      最近更新 更多