[英]Poor query performance PostgreSQL
我有一個問題:
SELECT
'{\"nombre\":\"'||c.column_name||'\",\"type\":\"'|| c.data_type
||'\",\"is_nullable\":\"'|| c.is_nullable||'\",\"is_pk\":\"'|| CASE WHEN constraint_type = 'PRIMARY KEY' THEN 'SI' ELSE 'NO' END
||'\",\"max_length\":\"'||COALESCE(c.character_maximum_length::VARCHAR,'')||'\",\"FK_schema\":\"'||COALESCE(ccu.table_schema,'')||'\",\"FK_tabla\":\"'||
COALESCE(ccu.table_name,'')||'\",\"FK_columna\":\"'||COALESCE(ccu.column_name,'')||
'\"}' as id, c.column_name
FROM information_schema.columns AS c
LEFT JOIN information_schema.key_column_usage i ON I.table_name=c.table_name AND I.table_schema=c.table_schema AND c.column_name = I.column_name
LEFT JOIN information_schema.table_constraints tc ON TC.constraint_name = I.CONSTRAINT_NAME AND constraint_type IN ('FOREIGN KEY','PRIMARY KEY')
LEFT JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
AND constraint_type IN ('FOREIGN KEY')
WHERE c.table_schema = '".$_POST['schema']."' AND c.table_name='".$_POST['tabla']."'
AND NOT EXISTS (
SELECT q.column_name FROM information_schema.constraint_column_usage q
inner join information_schema.table_constraints USING(constraint_name )
WHERE c.table_schema = q.table_schema AND q.table_name=c.table_name AND q.column_name = c.column_name
AND tc.constraint_name > q.constraint_name AND TC.constraint_type <> 'PRIMARY KEY')
ORDER BY c.ordinal_position;
它可以工作,但在具有97個模式的數據庫中,它需要一分鍾才能運行。
我怎樣才能解決這個問題?
沒有這一行:
LEFT JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name AND constraint_type = 'FOREIGN KEY'
它只需不到1秒鍾。
由於查詢似乎都是關於數據庫的Postgres元數據,因此可能不會像查詢中的常規表組那樣經常更改。
因此,我建議您使用物化視圖 ,該視圖設置為在您認為可接受的數據貨幣的某個時間間隔內刷新。 也許這是每小時或每天 - 這一切都取決於這些數據的變化頻率,以及您需要它的當前頻率(它們也是相互關聯的)。
所以你會這樣做:
CREATE MATERIALIZED VIEW mat_view AS
SELECT
'{\"nombre\":\"'||c.column_name||'\",\"type\":\"'|| c.data_type
||'\",\"is_nullable\":\"'|| c.is_nullable||'\",\"is_pk\":\"'|| CASE WHEN constraint_type = 'PRIMARY KEY' THEN 'SI' ELSE 'NO' END
||'\",\"max_length\":\"'||COALESCE(c.character_maximum_length::VARCHAR,'')||'\",\"FK_schema\":\"'||COALESCE(ccu.table_schema,'')||'\",\"FK_tabla\":\"'||
COALESCE(ccu.table_name,'')||'\",\"FK_columna\":\"'||COALESCE(ccu.column_name,'')||
'\"}' as id, c.column_name
FROM information_schema.columns AS c
LEFT JOIN information_schema.key_column_usage i ON I.table_name=c.table_name AND I.table_schema=c.table_schema AND c.column_name = I.column_name
LEFT JOIN information_schema.table_constraints tc ON TC.constraint_name = I.CONSTRAINT_NAME AND constraint_type IN ('FOREIGN KEY','PRIMARY KEY')
LEFT JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
AND constraint_type IN ('FOREIGN KEY')
WHERE c.table_schema = '".$_POST['schema']."' AND c.table_name='".$_POST['tabla']."'
AND NOT EXISTS (
SELECT q.column_name FROM information_schema.constraint_column_usage q
inner join information_schema.table_constraints USING(constraint_name )
WHERE c.table_schema = q.table_schema AND q.table_name=c.table_name AND q.column_name = c.column_name
AND tc.constraint_name > q.constraint_name AND TC.constraint_type <> 'PRIMARY KEY')
ORDER BY c.ordinal_position;
這實際上會在第一次運行時創建此視圖結果的快照。 然后可以通過REFRESH MATERIALIZED VIEW mat_view;
您可能還希望使用CONCURRENTLY
選項,該選項可防止阻止,但可能需要更長時間。
可以將REFRESH MATERIALIZED VIEW
命令放在cron上,以確保按照您希望的間隔完成。
注意:物化視圖是Postgres 9.3中的新功能。 CONCURRENTLY
在Postgres的 9.4增加。
編輯以回應OP的評論:
關於Postgres 8.4 ,聽起來好像不受你的控制,但你可能想要使用這些信息來游說服務器管理員和DBA,看看它是否改變了主意:
至於你在8.4上可以做些什么,它肯定會受到更多的限制......你可以試試的一件事可能會給你帶來一些改進(雖然不像后面的版本中的物化視圖那么多)是試圖打破JOIN
幾個不同的臨時表 。 這可能允許查詢規划器更好地推理每個單獨的查詢並且比整體更快地處理部件,盡管它肯定是依賴於數據,服務器調整和其他因素的高度可變的事物。
另外,嘗試在查詢之前在WHERE
中的NOT EXISTS
表達式中為子選擇創建臨時表 ,然后使用它。
確保它(以及其他臨時表)具有您可能需要的任何索引,以便它可以盡可能多地執行索引掃描而不是完整索引掃描。 請參閱EXPLAIN
語句( PgAdmin也提供了一個可視化語句),以幫助查看查詢計划程序對查詢啟動的看法以及在將其分解為組件時如何更改。
我做了一個新的查詢閱讀這個postgressql ...
select
'{\"nombre\":\"'||columna.attname||'\",\"tipo\":\"'|| tipo.typname
||'\",\"is_nullable\":\"'|| CASE WHEN columna.attnotnull THEN 'NO' ELSE 'SI' END||'\",\"is_pk\":\"'|| CASE WHEN pk.conname IS NULL THEN 'NO' ELSE 'SI' END
||'\",\"max_length\":\"'||COALESCE(character_maximum_length::varchar,'')||'\",\"FK_schema\":\"'||COALESCE(fk_schema.nspname,'')||'\",\"FK_tabla\":\"'||
COALESCE(fk_tabla.relname,'')||'\",\"FK_columna\":\"'||COALESCE(fk_columna.attname,'')||
'\"}' as id, columna.attname,columna.*
from pg_catalog.pg_namespace pgschema
inner join pg_catalog.pg_class clase ON PGSCHEMA.OID = clase.relnamespace and relname ='".$_POST['tabla']."'
inner join pg_catalog.pg_attribute columna ON ATtReLID = clase.oid
inner join pg_catalog.pg_type tipo ON tipo.oid = columna.atttypid
inner join information_schema.columns ON table_schema = pgschema.nspname AND table_name = clase.relname AND column_name = columna.attname
left join pg_catalog.pg_constraint pk ON pk.contype = 'p' AND PK.conrelid = clase.oid and array[columna.attnum] && pk.conkey
left join pg_catalog.pg_constraint Fk ON FK.contype = 'f' AND FK.conrelid = clase.oid and array[columna.attnum] && fk.conkey
left join pg_catalog.pg_class Fk_tabla ON FK.confrelid = fk_tabla.oid -- AND FK.conrelid = clase.oid and array[columna.attnum] && fk.conkey
left join pg_catalog.pg_namespace Fk_schema ON FK_tabla.relnamespace = fk_schema.oid
left join pg_catalog.pg_attribute fk_columna ON fk_tabla.OID = fk_columna.attrelid AND ARRAY[fk_columna.attnum] && fk.confkey
where pgschema.nspname = '".$_POST['schema']."' and columna.attnum > 0;
它只需不到1秒鍾。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.