Performance PostgreSQL:根据所有表字段的长度创建索引

Performance PostgreSQL:根据所有表字段的长度创建索引,performance,postgresql,database-performance,database-indexes,Performance,Postgresql,Database Performance,Database Indexes,我有一个名为profile的表格,我想按填写最多的表格排序。每列都是JSONB列或文本列。我在很大程度上不需要这个,所以我通常会订购如下: SELECT * FROM profile ORDER BY LENGTH(CONCAT(profile.*)) DESC; 但是,这很慢,所以我想创建一个索引。但是,这不起作用: CREATE INDEX index_name ON profile (LENGTH(CONCAT(*)) 也不是 CREATE INDEX index_name ON pr

我有一个名为
profile
的表格,我想按填写最多的表格排序。每列都是JSONB列或文本列。我在很大程度上不需要这个,所以我通常会订购如下:

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))))

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

您可以声明错误标记为“不可变”的函数,并在此基础上构建索引

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;

由于函数被错误地标记为不可变,如果您在表上添加或删除列,或更改列的类型,索引可能会过期。

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

SELECT length(profile::text) FROM profile;
但索引中的此表达式存在3(或4)个问题:

  • CREATE INDEX
    中不接受语法速记
    profile::text
    ,您需要在标准语法
    cast(profile AS text)中添加额外的括号或默认值

  • 仍然存在同样的问题:索引表达式中只允许使用
    不可变的
    函数,而将行类型强制转换为
    文本
    不能满足此要求。您可以构建一个伪
    不可变的
    包装函数,如Jeff所述

  • 存在一种固有的模糊性(这也适用于Jeff的答案!):如果列名与表名相同(这是一种常见情况),则不能在
    创建索引中引用行类型,因为标识符总是首先解析为列名

  • 与原始版本稍有不同:这会在
    文本
    表示中添加列分隔符、行装饰符以及可能的转义字符。对您的用例来说应该没有多大关系

  • 然而,我建议使用更激进的替代方法作为行大小的粗略指标:。甚至更短更快,避免了问题1、3和4:

    问题2仍然存在:
    pg\u column\u size()
    也只是
    稳定的
    。您可以创建一个简单而廉价的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\u column\u size()
    时,我们的自定义函数将根据规则进行更紧密的匹配,并被选中,而不是多态系统函数。或者,使用单独的名称,并可能使函数具有多态性

    相关的:

    “不工作”是对问题的拙劣描述。
    CREATE OR REPLACE FUNCTION pg_column_size(profile)
      RETURNS int LANGUAGE sql IMMUTABLE AS
    'SELECT pg_catalog.pg_column_size($1)';