mai*_*rgs 308 sql database postgresql foreign-keys
Postgres会自动将索引放在外键和主键上吗?我该怎么说?是否有一个命令可以返回表上的所有索引?
Phi*_*ipp 366
PostgreSQL自动在主键和唯一约束上创建索引,但不在外键关系的引用端创建索引.
当Pg创建一个隐式索引时,它将发出一个NOTICE
你可以在psql
系统日志和/或系统日志中看到的级别消息,这样你就可以看到它何时发生.自动创建的索引也在\d
表的输出中可见.
PostgreSQL自动为每个唯一约束和主键约束创建索引以强制唯一性.因此,没有必要为主键列显式创建索引.
关于约束的文档说:
由于引用表中的行的DELETE或引用列的UPDATE将需要扫描引用表以查找与旧值匹配的行,因此通常最好对引用列建立索引.因为并不总是需要这个,并且有很多关于如何索引的选择,所以外键约束的声明不会自动在引用列上创建索引.
因此,如果需要,您必须自己在外键上创建索引.
请注意,如果您使用主外键,例如2 FK作为M-to-N表中的PK,您将拥有PK的索引,并且可能不需要创建任何额外的索引.
虽然在引用端外键列上创建索引(或包括)通常是个好主意,但这不是必需的.每次添加索引减慢DML操作略有下降,所以你在每交纳履约成本INSERT
,UPDATE
或DELETE
.如果很少使用该索引,则可能不值得拥有.
dla*_*and 33
如果要从程序中列出架构中所有表的索引,则所有信息都在目录中:
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
Run Code Online (Sandbox Code Playgroud)
如果您想进一步深入研究(例如列和排序),您需要查看pg_catalog.pg_index.使用psql -E [dbname]
派上用场搞清楚如何查询目录.
Ser*_*eyB 24
此查询将列出外键,原始源上的缺失索引.
-- 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;
Run Code Online (Sandbox Code Playgroud)
Mil*_*dev 20
是 - 对于主键,否 - 对于外键(在文档中更多).
\d <table_name>
Run Code Online (Sandbox Code Playgroud)
in "psql"显示包含其所有索引的表的描述.
Nab*_*abi 12
我喜欢在EclipseLink 2.5的Cool performance features文章中解释这一点
索引外键
第一个功能是自动索引外键.大多数人错误地认为数据库默认情况下索引外键.好吧,他们没有.主键是自动索引的,但外键不是.这意味着任何基于外键的查询都将进行全表扫描.这是任何OneToMany, ManyToMany或ElementCollection关系,以及许多 OneToOne 关系,以及涉及连接或对象比较的任何关系的大多数查询.这可能是一个主要的执行问题,您应始终索引外键字段.
对于a PRIMARY KEY
,将使用以下消息创建索引:
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "index" for table "table"
Run Code Online (Sandbox Code Playgroud)
对于FOREIGN KEY
,约束也不会,如果有对和借鉴没有索引创建编表.
上和借鉴索引ING表不是必需的(尽管需要的话),并且因此将不被隐式地创建.
此函数基于 Laurenz Albe 在https://www.cybertec-postgresql.com/en/index-your-foreign-key/上的工作,列出所有缺少索引的外键。显示了表的大小,对于小表,扫描性能可能优于索引表。
--
-- function: fkeys_missing_indexes
-- purpose: list all foreing keys in the database without and index in the source table.
-- author: Laurenz Albe
-- see: https://www.cybertec-postgresql.com/en/index-your-foreign-key/
--
create or replace function oftool_fkey_missing_indexes ()
returns table (
src_table regclass,
fk_columns varchar,
table_size varchar,
fk_constraint name,
dst_table regclass
)
as $$
select
-- source table having ta foreign key declaration
tc.conrelid::regclass as src_table,
-- ordered list of foreign key columns
string_agg(ta.attname, ',' order by tx.n) as fk_columns,
-- source table size
pg_catalog.pg_size_pretty (
pg_catalog.pg_relation_size(tc.conrelid)
) as table_size,
-- name of the foreign key constraint
tc.conname as fk_constraint,
-- name of the target or destination table
tc.confrelid::regclass as dst_table
from pg_catalog.pg_constraint tc
-- enumerated key column numbers per foreign key
cross join lateral unnest(tc.conkey) with ordinality as tx(attnum, n)
-- name for each key column
join pg_catalog.pg_attribute ta on ta.attnum = tx.attnum and ta.attrelid = tc.conrelid
where not exists (
-- is there ta matching index for the constraint?
select 1 from pg_catalog.pg_index i
where
i.indrelid = tc.conrelid and
-- the first index columns must be the same as the key columns, but order doesn't matter
(i.indkey::smallint[])[0:cardinality(tc.conkey)-1] @> tc.conkey) and
tc.contype = 'f'
group by
tc.conrelid,
tc.conname,
tc.confrelid
order by
pg_catalog.pg_relation_size(tc.conrelid) desc;
$$ language sql;
Run Code Online (Sandbox Code Playgroud)
这样测试一下
select * from oftool_fkey_missing_indexes();
Run Code Online (Sandbox Code Playgroud)
你会看到一个这样的列表。
fk_columns |table_size|fk_constraint |dst_table |
----------------------|----------|----------------------------------|-----------------|
id_group |0 bytes |fk_customer__group |im_group |
id_product |0 bytes |fk_cart_item__product |im_store_product |
id_tax |0 bytes |fk_order_tax_resume__tax |im_tax |
id_product |0 bytes |fk_order_item__product |im_store_product |
id_tax |0 bytes |fk_invoice_tax_resume__tax |im_tax |
id_product |0 bytes |fk_invoice_item__product |im_store_product |
id_article,locale_code|0 bytes |im_article_comment_id_article_fkey|im_article_locale|
Run Code Online (Sandbox Code Playgroud)