小编典典

PostgreSQL:如何索引所有外键?

sql

我正在使用大型PostgreSQL数据库,并且正在尝试对其进行调整以提高性能。

我们的查询和更新似乎正在使用外键进行大量查找。

我想要的是一种相对简单的方法,可以将索引添加到我们所有的外键中,而不必遍历每个表(〜140)并手动进行。

通过研究,我发现没有办法让Postgres自动为您做到这一点(就像MySQL一样),但是我也很高兴听到其他情况。


阅读 333

收藏
2021-04-15

共1个答案

小编典典

编辑 :因此,我在下面编写了查询,然后想到…“等等,Postgresql要求外键目标必须具有唯一索引。”
所以我想我误会了你的意思?您可以使用以下查询通过将“ conrelid”替换为“ confrelid”,将“ conkey”替换为“
confkey”来检查外键的 是否具有索引(是,是,查询中没有别名…)

好吧,我想应该可以遍历系统目录…像往常一样,对系统目录的最佳指南是使用psql并执行“ \ set ECHO_HIDDEN 1”,然后查看它为有趣的“
\”生成的SQL。 d”命令。这是用于查找表(“ \ d tablename”)的外键的SQL:

-- $1 is the table OID, e.g. 'tablename'::regclass
SELECT conname, conrelid::pg_catalog.regclass,
  pg_catalog.pg_get_constraintdef(c.oid, true) as condef
FROM pg_catalog.pg_constraint c
WHERE c.confrelid = $1 AND c.contype = 'f' ORDER BY 1;

似乎pg_constraint有列conkeyconfkey并且看起来像是定义键所跨越的列号。可能confkey是外表中的列号,因为外键只为非空。另外,花了一段时间我才意识到这是SQL来显示
引用 给定表的外键。无论如何,这就是我们想要的。

因此,此查询显示数据开始成形:

select confrelid, conname, column_index, attname
from pg_attribute
     join (select confrelid::regclass, conname, unnest(confkey) as column_index
           from pg_constraint
           where confrelid = 'ticket_status'::regclass) fkey
          on fkey.confrelid = pg_attribute.attrelid
             and fkey.column_index = pg_attribute.attnum

我将使用8.4功能,例如unnest
…您也许可以相处得很好。

我最终得到了:

select pg_index.indexrelid::regclass, 'create index ' || relname || '_' ||
         array_to_string(column_name_list, '_') || '_idx on ' || confrelid ||
         ' (' || array_to_string(column_name_list, ',') || ')'
from (select distinct
       confrelid,
       array_agg(attname) column_name_list,
       array_agg(attnum) as column_list
     from pg_attribute
          join (select confrelid::regclass,
                 conname,
                 unnest(confkey) as column_index
                from (select distinct
                        confrelid, conname, confkey
                      from pg_constraint
                        join pg_class on pg_class.oid = pg_constraint.confrelid
                        join pg_namespace on pg_namespace.oid = pg_class.relnamespace
                      where nspname !~ '^pg_' and nspname <> 'information_schema'
                      ) fkey
               ) fkey
               on fkey.confrelid = pg_attribute.attrelid
                  and fkey.column_index = pg_attribute.attnum
     group by confrelid, conname
     ) candidate_index
join pg_class on pg_class.oid = candidate_index.confrelid
left join pg_index on pg_index.indrelid = confrelid
                      and indkey::text = array_to_string(column_list, ' ')

好的,此怪兽会打印出候​​选索引命令,并尝试将其与现有索引匹配。因此,您只需在末尾添加“ where
indexrelid为null”,即可获得创建似乎不存在的索引的命令。

该查询不能很好地处理多列外键;但是,恕我直言,如果您使用的是这些,那您应该得到麻烦。

LATER EDIT :这是带有建议的编辑的查询,位于顶部。因此,这显示了在不作为外键(而不是目标)来源的列上创建不存在的索引的命令。

select pg_index.indexrelid::regclass, 'create index ' || relname || '_' ||
         array_to_string(column_name_list, '_') || '_idx on ' || conrelid ||
         ' (' || array_to_string(column_name_list, ',') || ')'
from (select distinct
       conrelid,
       array_agg(attname) column_name_list,
       array_agg(attnum) as column_list
     from pg_attribute
          join (select conrelid::regclass,
                 conname,
                 unnest(conkey) as column_index
                from (select distinct
                        conrelid, conname, conkey
                      from pg_constraint
                        join pg_class on pg_class.oid = pg_constraint.conrelid
                        join pg_namespace on pg_namespace.oid = pg_class.relnamespace
                      where nspname !~ '^pg_' and nspname <> 'information_schema'
                      ) fkey
               ) fkey
               on fkey.conrelid = pg_attribute.attrelid
                  and fkey.column_index = pg_attribute.attnum
     group by conrelid, conname
     ) candidate_index
join pg_class on pg_class.oid = candidate_index.conrelid
left join pg_index on pg_index.indrelid = conrelid
                      and indkey::text = array_to_string(column_list, ' ')
where indexrelid is null

我的经验是,这实际上并没有那么有用。它建议为诸如引用代码之类的东西创建索引,这些索引实际上不需要索引。

2021-04-15