2009-06-09 139 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 關係,大多數查詢都是對涉及任何關係連接或 的對象比較。這可能是一個主要的執行問題,您應該始終索引您的外鍵字段。