我正在使用一個大型的PostgreSQL數據庫,我試圖調整它以獲得更多的性能。PostgreSQL:如何索引所有外鍵?
我們的查詢和更新似乎在使用外鍵進行大量查找。
我想要的是一種相對簡單的方法,可以將索引添加到所有外鍵,而無需通過每個表(〜140)並手動執行。
在研究這件事時,我發現Postgres沒有辦法讓你自動爲你做這件事(就像MySQL一樣),但是我也很樂意聽到它。
我正在使用一個大型的PostgreSQL數據庫,我試圖調整它以獲得更多的性能。PostgreSQL:如何索引所有外鍵?
我們的查詢和更新似乎在使用外鍵進行大量查找。
我想要的是一種相對簡單的方法,可以將索引添加到所有外鍵,而無需通過每個表(〜140)並手動執行。
在研究這件事時,我發現Postgres沒有辦法讓你自動爲你做這件事(就像MySQL一樣),但是我也很樂意聽到它。
編輯:所以,我寫了下面的查詢,然後想......「等等,Postgresql要求外鍵目標必須有唯一索引。所以我想我誤解了你的意思?你可以使用下面的查詢來檢查你的外鍵的源有索引,通過用「confrelid」代替「confrelid」和「conkey」代替「confkey」(是的,沒錯,在查詢中沒有別名...)
嗯,我猜應該可以通過系統目錄...像往常一樣,系統目錄的最佳指南是使用psql並執行「\ set ECHO_HIDDEN 1」,然後查看它生成的SQL爲有趣的「\ d」命令。下面是用於查找表的外鍵的SQL(「\ d表名」):
-- $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有像他們可能是列數,關鍵是整個定義的列conkey
和confkey
。可能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
我要使用像unnest 8.4功能...你也許能夠不相處。
我結束了:
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, ' ')
OK,這個畸形打印出候選索引命令,並試圖對其進行匹配與現有的指數。因此,您可以簡單地在末尾添加「where indexrelid爲null」以獲取命令來創建似乎不存在的索引。
該查詢不能很好地處理多列外鍵;但是如果你使用這些,你應該得到麻煩。
後編輯:這裏是查詢與建議編輯在頂部放在英寸所以這表明創建索引不存在的命令,在外鍵的來源列(不是它的目標)。
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
我的經驗是,這不是真的有用。它建議爲諸如參考代碼之類的東西創建索引,這些索引代碼實際上不需要進行索引。
該信息是在catalog tables之內。但它似乎並不是非常簡單的做你想要的,特別是如果已經創建了一些索引(以及多列索引怎麼樣...)
如果你沒有任何索引FK,你可以做一些快速和骯髒的,因爲
SELECT 'CREATE INDEX ' || table_name || '_' || column_name || '_idx ON '
|| table_name || '(' || column_name || ');'
from foreign_key_tables where schema = 'public';
你會跟你有興趣的模式取代,轉儲到一個文件,編輯,查看,祈禱和飼料給psql。請注意,此過程不會檢測已存在的索引。
啊,foreign_key_tables
是創建一個信息視圖:
CREATE VIEW foreign_key_tables AS SELECT
n.nspname AS schema,
cl.relname AS table_name,
a.attname AS column_name,
ct.conname AS key_name,
nf.nspname AS foreign_schema,
clf.relname AS foreign_table_name,
af.attname AS foreign_column_name,
pg_get_constraintdef(ct.oid) AS create_sql
FROM pg_catalog.pg_attribute a
JOIN pg_catalog.pg_class cl ON (a.attrelid = cl.oid AND cl.relkind =
'r')
JOIN pg_catalog.pg_namespace n ON (n.oid = cl.relnamespace)
JOIN pg_catalog.pg_constraint ct ON (a.attrelid = ct.conrelid AND
ct.confrelid != 0 AND ct.conkey[1] = a.attnum)
JOIN pg_catalog.pg_class clf ON (ct.confrelid = clf.oid AND clf.relkind
= 'r')
JOIN pg_catalog.pg_namespace nf ON (nf.oid = clf.relnamespace)
JOIN pg_catalog.pg_attribute af ON (af.attrelid = ct.confrelid AND
af.attnum = ct.confkey[1]);
這看起來更像我以後。可悲的是,我的表/列名稱太長,不能直接運行。讓我玩一下。 – biggusjimmus 2010-06-04 16:17:51
leonbloy!很好的解決方案!這是我正在尋找的,因爲我不能在nhibernate映射文件(hbm)中創建這些索引。我最後的解決方案是執行sql腳本。 – 2011-08-08 00:47:59
我創建了這個代碼的腳本,似乎有點短:
的最後一行,如果SELECT 'DROP INDEX IF EXISTS fk_' || conname || '_idx; CREATE INDEX fk_' || conname || '_idx ON '
|| relname || ' ' ||
regexp_replace(
regexp_replace(pg_get_constraintdef(pg_constraint.oid, true),
' REFERENCES.*$','',''), 'FOREIGN KEY ','','') || ';'
FROM pg_constraint
JOIN pg_class
ON (conrelid = pg_class.oid)
JOIN pg_namespace
ON (relnamespace = pg_namespace.oid)
WHERE contype = 'f'
AND nspname = 'public'
--AND 'fk_' || conname || '_idx' NOT IN (SELECT indexname FROM pg_indexes)
;
評論你不想重新創建已經存在的索引
編輯之後,這看起來好像可以工作,我要運行這個和leonbloy的回答之間的比較 – biggusjimmus 2010-06-04 16:19:40
這一個不顯示外鍵,但只有主鍵。這是沒有意義的,因爲你不需要pk的索引,因爲pk約束「是」索引 – 2010-11-04 10:14:46
@peperg否,查詢直接與主鍵沒有任何關係:它找到外鍵的目標。當然,如果你的數據庫設計得很好,那麼外鍵的目標就是主鍵。注意頂部的編輯表明如何改變它以找出外鍵的* source *沒有被索引的地方實際上不是太有用的imho)。對於混淆抱歉,答案可能應該重寫。 – araqnid 2010-11-05 00:46:55