【发布时间】:2015-04-17 22:43:12
【问题描述】:
我有一个非常大的 postgres 数据库,其中有一个特定的模式,该模式被放入并每晚重新创建。创建该模式中的所有表后,我想对它们进行真空分析,但是数据库太大了,如果一个完整的数据库VACUUM ANALYZE; 需要大约半小时。
如何在不为每个表编写单独的 SQL 命令的情况下仅对此架构中的每个表进行真空分析?
【问题讨论】:
标签: postgresql
我有一个非常大的 postgres 数据库,其中有一个特定的模式,该模式被放入并每晚重新创建。创建该模式中的所有表后,我想对它们进行真空分析,但是数据库太大了,如果一个完整的数据库VACUUM ANALYZE; 需要大约半小时。
如何在不为每个表编写单独的 SQL 命令的情况下仅对此架构中的每个表进行真空分析?
【问题讨论】:
标签: postgresql
下面的 bash 函数利用 CLI 工具 psql 对单个模式中的表进行真空分析,可以通过将模式名称作为第一个参数传递给函数或设置环境变量 PG_SCHEMA 来识别该表:
vacuum_analyze_schema() {
# vacuum analyze only the tables in the specified schema
# postgres info can be supplied by either passing it as parameters to this
# function, setting environment variables or a combination of the two
local pg_schema="${1:-${PG_SCHEMA}}"
local pg_db="${2:-${PG_DB}}"
local pg_user="${3:-${PG_USER}}"
local pg_host="${4:-${PG_HOST}}"
echo "Vacuuming schema \`${pg_schema}\`:"
# extract schema table names from psql output and put them in a bash array
local psql_tbls="\dt ${pg_schema}.*"
local sed_str="s/${pg_schema}\s+\|\s+(\w+)\s+\|.*/\1/p"
local table_names=$( echo "${psql_tbls}" | psql -d "${pg_db}" -U "${pg_user}" -h "${pg_host}" | sed -nr "${sed_str}" )
local tables_array=( $( echo "${table_names}" | tr '\n' ' ' ) )
# loop through the table names creating and executing a vacuum
# command for each one
for t in "${tables_array[@]}"; do
echo "doing table \`${t}\`..."
psql -d "${pg_db}" -U "${pg_user}" -h "${pg_host}" \
-c "VACUUM (ANALYZE) ${pg_schema}.${t};"
done
}
可以将此函数添加到您的.bashrc 中,以便随时从命令行调用它。与模式一样,Postgres 连接和数据库值可以通过将它们作为函数参数提供来设置:
# params must be in this order
vacuum_analyze_schema '<your-pg-schema>' '<your-pg-db>' '<your-pg-user>' '<your-pg-host>'
或者通过设置环境变量:
PG_SCHEMA='<your-pg-schema>'
PG_USER='<your-pg-user>'
PG_HOST='<your-pg-host>'
PG_DB='<your-pg-db>'
vacuum_analyze_schema
或两者兼而有之。作为参数传递的值将优先于相应的环境变量。
【讨论】:
可以使用下面的pl/pgsql脚本(如果只想分析,vacuum不能从函数或多命令字符串执行):
DO $$
DECLARE
tab RECORD;
schemaName VARCHAR := 'your_schema';
BEGIN
for tab in (select t.relname::varchar AS table_name
FROM pg_class t
JOIN pg_namespace n ON n.oid = t.relnamespace
WHERE t.relkind = 'r' and n.nspname::varchar = schemaName
order by 1)
LOOP
RAISE NOTICE 'ANALYZE %.%', schemaName, tab.table_name;
EXECUTE format('ANALYZE %I.%I', schemaName, tab.table_name);
end loop;
end
$$;
【讨论】:
format() 对动态SQL 更安全地处理可能需要引用的标识符:EXECUTE format('ANALYZE %I.%I', schemaName, tab.table_name);
难道不是更简单:
psql -t -A -U postgres -c "select format('analyse verbose %I.%I;', n.nspname::varchar, t.relname::varchar) FROM pg_class t JOIN pg_namespace n ON n.oid = t.relnamespace WHERE t.relkind = 'r' and n.nspname::varchar = 'your_schema' order by 1" | psql -U postgres
选项 -t 只打印行(无标题)和 -A 避免格式化
【讨论】:
基于@Grant Humphries 和@Fritz 的解决方案,但更短更简单:
PGUSER=your_postgres_username
PGHOST=your_postgres_host
PGPORT=your_postgres_port
PGDB=your_postgres_db_name
PGSCHEMA=your_postgres_schema
for table in $(psql -h ${PGHOST} -p ${PGPORT} -d ${PGDB} -U ${PGUSER} \
-c "select tablename from pg_tables where schemaname = '${PGSCHEMA}';" | \
tail -n +3 | head -n -2); do
psql -h ${PGHOST} -p ${PGPORT} -d ${PGDB} -U ${PGUSER} \
-c "VACUUM (ANALYZE) ${PGSCHEMA}.${table};";
done
与上述解决方案的区别:
【讨论】:
在寻找这个确切问题的答案时,我发现 PPH 给出的解决方法更可取。不幸的是,给定的命令行不能开箱即用(在 Postgres 服务器 v9.6.13 上使用 psql 10.8 进行了测试)。
这是我成功用于VACUUM ANALYZE特定PostgreSQL数据库中特定模式的所有表的命令行:
psql -t -A -d "YOUR_DATABASE" -c "select format('vacuum analyse verbose %I.%I;', n.nspname::varchar, t.relname::varchar) FROM pg_class t JOIN pg_namespace n ON n.oid = t.relnamespace WHERE t.relkind = 'r' and n.nspname::varchar = 'YOUR_SCHEMA' order by 1" | psql -U postgres -d "YOUR_DATABASE"
您必须将三个大写术语替换为适用于您的情况的值。对我来说完美无缺。
【讨论】:
do
$$
declare
r record;
schemaname varchar := 'contact';
begin
perform dblink_connect('vacuum_connection', 'dbname=' || current_database());
for r in ( select t.oid::regclass::text tname
from pg_class t
where t.relkind = 'r' and t.relnamespace = schemaname::regnamespace)
loop
raise notice '%1', r.tname;
perform dblink_exec('vacuum_connection', 'vacuum analyze ' || r.tname);
end loop;
perform dblink_disconnect('vacuum_connection');
end
$$
【讨论】: