我有一个非常大的postgres数据库,其中有一个特定的模式,它被放入并在每晚重新创建。在创建该模式中的所有表之后,我想对它们进行真空分析,但是数据库是如此之大,以至于如果执行完整的数据库VACUUM ANALYZE;
则需要大约半小时。
如何在不为每个表编写单独的SQL命令的情况下,真正分析此模式中的每个表?
答案 0 :(得分:9)
下面的bash函数利用psql真空分析模式中由变量$PGSCHEMA
完全披露:我在发布问题之前制定了这个答案,但认为这对其他人有用,并且很想看到任何其他解决方案。
PGUSER=your_postgres_username
PGHOST=your_postgres_host
PGDBNAME=your_postgres_db_name
PGSCHEMA=your_postgres_schema
vacuum_analyze_schema() {
# vacuum analyze only the tables in the schema named in the variable $PGSCHEMA
psql_tbls="\dt $PGSCHEMA.*"
sed_str="s/$PGSCHEMA\s+\|\s+(\w+)\s+\|.*/\1/p"
# extract schema table names from psql output and put them in a bash array
echo "$psql_tbls | psql -d $PGDBNAME -U $PGUSER -h $PGHOST | sed -nr '$sed_str'"
table_names=$(echo "$psql_tbls" | psql -d $PGDBNAME -U $PGUSER -h $PGHOST | sed -nr "$sed_str")
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
q="VACUUM ANALYZE $PGSCHEMA.$t;"
echo "psql -d $PGDBNAME -U $PGUSER -h $PGHOST -c $q"
psql -d $PGDBNAME -U $PGUSER -h $PGHOST -c "$q"
done
}
vacuum_analyze_schema;
答案 1 :(得分:3)
您可以使用以下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 %1.%2', schemaName, tab.table_name;
EXECUTE 'ANALYZE '||schemaName||'.'||tab.table_name;
end loop;
end
$$;
答案 2 :(得分:1)
一种基于@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
与上述解决方案的区别:
答案 3 :(得分:0)
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
$$
答案 4 :(得分:0)
难道不是很简单吗?
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避免格式化
答案 5 :(得分:0)
在寻找这个确切问题的答案时,我发现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"
您必须将三个大写字母替换为适用于您的案例的值。为我完美地工作。