2009-06-09 124 views

回答

264

PostgreSQL自动在主键和唯一约束上创建索引,但不在外键关系的引用端创建索引。

当Pg创建隐式索引时,它将发出一个NOTICE级别的消息,您可以在psql和/或系统日志中看到,以便您可以看到它何时发生。自动创建的索引在\d输出中也可见。

documentation on unique indexes的说:

PostgreSQL自动为每个唯一约束和主键约束强制唯一性的指标。因此,没有必要为主键列显式创建索引。

constraints的文件说:

由于删除引用表或 引用的列的更新行的,需要引用表的 行匹配的扫描旧值的情况下,索引 引用列通常是个好主意。因为这并不总是需要的,并且 有许多关于如何索引的选项,所以外键约束的声明 约束不会自动在引用 列中创建索引。

因此,如果您需要,您必须自己在外键上创建索引。

请注意,如果您使用主键 - 外键,如2 FK作为M到N表中的PK,则您将拥有PK索引,并且可能不需要创建任何额外索引。

虽然在引用端外键列上创建索引通常是一个好主意,但并不是必需的。您添加的每个索引都会使DML操作略微减慢,因此您需要为每个INSERTUPDATEDELETE支付一次性能成本。如果该指数很少使用,它可能不值得拥有。

+19

我希望这个编辑是好的;我已经添加了相关文档的链接,这个引用使得它完全明确地指出FK关系的引用方不会产生隐式索引,显示了如何在psql中查看索引,为了清晰起见而修改了第一个参数,并添加了一个请注意,索引不是免费的,所以添加它们并不总是正确的。 – 2012-08-23 05:16:32

+0

@CraigRinger,你如何确定指数的收益是否超过其成本?我是否在添加索引之前/之后对单元测试进行剖析并检查总体性能增益?或者,还有更好的方法? – Gili 2014-11-25 05:00:32

+0

@Gili这是一个单独的dba.stackexchange.com问题的主题。 – 2014-11-25 05:04:09

19

是 - 对于主键,不是 - 对于外键(更多位于docs)。

\d <table_name> 

in "psql"显示包括其所有索引的表的描述。

+9

对于参考\ di也会列出数据库中的所有索引。 – Daemin 2010-02-19 04:42:03

7

对于PRIMARY KEY,索引将使用以下信息来创建:

NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "index" for table "table" 

对于FOREIGN KEY,约束不会如果有上中借鉴表中没有索引创建。

有关引用的索引ing表不是必需的(尽管需要),因此不会被隐式创建。

26

如果要列出所有表的索引,从你的程序的模式(S),所有的信息是手头上的目录:

select 
    n.nspname as "Schema" 
    ,t.relname as "Table" 
    ,c.relname as "Index" 
from 
      pg_catalog.pg_class c 
    join pg_catalog.pg_namespace n on n.oid  = c.relnamespace 
    join pg_catalog.pg_index i  on i.indexrelid = c.oid 
    join pg_catalog.pg_class t  on i.indrelid = t.oid 
where 
     c.relkind = 'i' 
    and n.nspname not in ('pg_catalog', 'pg_toast') 
    and pg_catalog.pg_table_is_visible(c.oid) 
order by 
    n.nspname 
    ,t.relname 
    ,c.relname 

如果你想进一步深入研究(例如作为列和排序),您需要查看pg_catalog.pg_index。使用psql -E [dbname]可以方便地找出如何查询目录。

10

此查询将列出外键丢失索引,original source

-- check for FKs where there is no matching index 
-- on the referencing side 
-- or a bad index 

WITH fk_actions (code, action) AS (
    VALUES ('a', 'error'), 
     ('r', 'restrict'), 
     ('c', 'cascade'), 
     ('n', 'set null'), 
     ('d', 'set default') 
), 
fk_list AS (
    SELECT pg_constraint.oid as fkoid, conrelid, confrelid as parentid, 
     conname, relname, nspname, 
     fk_actions_update.action as update_action, 
     fk_actions_delete.action as delete_action, 
     conkey as key_cols 
    FROM pg_constraint 
     JOIN pg_class ON conrelid = pg_class.oid 
     JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid 
     JOIN fk_actions AS fk_actions_update ON confupdtype = fk_actions_update.code 
     JOIN fk_actions AS fk_actions_delete ON confdeltype = fk_actions_delete.code 
    WHERE contype = 'f' 
), 
fk_attributes AS (
    SELECT fkoid, conrelid, attname, attnum 
    FROM fk_list 
     JOIN pg_attribute 
      ON conrelid = attrelid 
      AND attnum = ANY(key_cols) 
    ORDER BY fkoid, attnum 
), 
fk_cols_list AS (
    SELECT fkoid, array_agg(attname) as cols_list 
    FROM fk_attributes 
    GROUP BY fkoid 
), 
index_list AS (
    SELECT indexrelid as indexid, 
     pg_class.relname as indexname, 
     indrelid, 
     indkey, 
     indpred is not null as has_predicate, 
     pg_get_indexdef(indexrelid) as indexdef 
    FROM pg_index 
     JOIN pg_class ON indexrelid = pg_class.oid 
    WHERE indisvalid 
), 
fk_index_match AS (
    SELECT fk_list.*, 
     indexid, 
     indexname, 
     indkey::int[] as indexatts, 
     has_predicate, 
     indexdef, 
     array_length(key_cols, 1) as fk_colcount, 
     array_length(indkey,1) as index_colcount, 
     round(pg_relation_size(conrelid)/(1024^2)::numeric) as table_mb, 
     cols_list 
    FROM fk_list 
     JOIN fk_cols_list USING (fkoid) 
     LEFT OUTER JOIN index_list 
      ON conrelid = indrelid 
      AND (indkey::int2[])[0:(array_length(key_cols,1) -1)] @> key_cols 

), 
fk_perfect_match AS (
    SELECT fkoid 
    FROM fk_index_match 
    WHERE (index_colcount - 1) <= fk_colcount 
     AND NOT has_predicate 
     AND indexdef LIKE '%USING btree%' 
), 
fk_index_check AS (
    SELECT 'no index' as issue, *, 1 as issue_sort 
    FROM fk_index_match 
    WHERE indexid IS NULL 
    UNION ALL 
    SELECT 'questionable index' as issue, *, 2 
    FROM fk_index_match 
    WHERE indexid IS NOT NULL 
     AND fkoid NOT IN (
      SELECT fkoid 
      FROM fk_perfect_match) 
), 
parent_table_stats AS (
    SELECT fkoid, tabstats.relname as parent_name, 
     (n_tup_ins + n_tup_upd + n_tup_del + n_tup_hot_upd) as parent_writes, 
     round(pg_relation_size(parentid)/(1024^2)::numeric) as parent_mb 
    FROM pg_stat_user_tables AS tabstats 
     JOIN fk_list 
      ON relid = parentid 
), 
fk_table_stats AS (
    SELECT fkoid, 
     (n_tup_ins + n_tup_upd + n_tup_del + n_tup_hot_upd) as writes, 
     seq_scan as table_scans 
    FROM pg_stat_user_tables AS tabstats 
     JOIN fk_list 
      ON relid = conrelid 
) 
SELECT nspname as schema_name, 
    relname as table_name, 
    conname as fk_name, 
    issue, 
    table_mb, 
    writes, 
    table_scans, 
    parent_name, 
    parent_mb, 
    parent_writes, 
    cols_list, 
    indexdef 
FROM fk_index_check 
    JOIN parent_table_stats USING (fkoid) 
    JOIN fk_table_stats USING (fkoid) 
WHERE table_mb > 9 
    AND (writes > 1000 
     OR parent_writes > 1000 
     OR parent_mb > 10) 
ORDER BY issue_sort, table_mb DESC, table_name, fk_name; 
6

我爱怎么这是文章Cool performance features of EclipseLink 2.5

索引外键

中介绍的第一个特点是外键的自动索引。大多数人错误地认为数据库默认索引 外键。那么,他们没有。主键为自动编号 ,但外键不是。这意味着任何基于 外键的查询都将进行全表扫描。这是任何一对多多对多ElementCollection关系,以及许多OneToOne 关系,大多数查询都是对涉及任何关系连接或 的对象比较。这可能是一个主要的执行问题,您应该始终索引您的外键字段。