sql - PostgreSQL:如何索引所有外键?

标签 sql database postgresql indexing foreign-keys

我正在使用一个大型 PostgreSQL 数据库,我正在尝试调整它以获得更高的性能。

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

我想要的是一种相对简单的方法,可以将索引添加到我们所有的外键,而无需遍历每个表 (~140) 并手动完成。

在研究这个过程中,我发现没有办法让 Postgres 自动为你做这件事(就像 MySQL 那样),但我也很乐意听到其他情况。

最佳答案

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

嗯,我想应该可以通过系统目录...和往常一样,系统目录的最佳指南是使用 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 is 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

我的经验是,这并不是真的那么有用。它建议为确实不需要编制索引的引用代码等内容创建索引。

关于sql - PostgreSQL:如何索引所有外键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2970050/

相关文章:

sql - 在SQL Server中创建表时如何限制INTEGER的长度?

sql - Azure SQL 数据库与 Azure 移动服务

带有内连接的 SQL 选择

sql - 查询数据库中的所有表

mysql - 如何选择最大值为 2 列的行

PHP 报告错误。 DB验证如何?

mysql - 数据库已经填充并运行后是否可以完成分片解决方案

mysql - MySQL 中的大型唯一键

python - 更新现有表/模型列/字段?

Postgresql base64 编码