【问题标题】:Vacuum analyze all tables in a schema postgres真空分析模式 postgres 中的所有表
【发布时间】:2015-04-17 22:43:12
【问题描述】:

我有一个非常大的 postgres 数据库,其中有一个特定的模式,该模式被放入并每晚重新创建。创建该模式中的所有表后,我想对它们进行真空分析,但是数据库太大了,如果一个完整的数据库VACUUM ANALYZE; 需要大约半小时。

如何在不为每个表编写单独的 SQL 命令的情况下仅对此架构中的每个表进行真空分析?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    下面的 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
    

    或两者兼而有之。作为参数传递的值将优先于相应的环境变量。

    【讨论】:

      【解决方案2】:

      可以使用下面的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);
      • 为什么不“从 pg_tables where schemaname = 'your_schema' 中选择 schemaname||'.'||tablename”?
      【解决方案3】:

      难道不是更简单:

      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 避免格式化

      【讨论】:

        【解决方案4】:

        基于@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
        

        与上述解决方案的区别:

        • 通过直接查询系统目录视图 pg_tables 获取表名。这样可以更轻松地提取表名,因为我们只需要使用 head 和 tail 删除输出中的页眉和页脚。
        • 为需要的安装添加了端口号。
        • 将vacuum 语句更新为带括号的当前(PostgreSQL 9.0 及更高版本)语法。根据documentation:“不推荐使用带括号的语法。”

        【讨论】:

        • 不错的解决方案,轻量级并且消除了难以解释的 sed 命令。
        【解决方案5】:

        在寻找这个确切问题的答案时,我发现 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"

        您必须将三个大写术语替换为适用于您的情况的值。对我来说完美无缺。

        【讨论】:

          【解决方案6】:
          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
          $$
          

          【讨论】:

          • 它是相关的,但我相信它被否决了,因为它需要 dblink 并且没有发布解释。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-21
          • 1970-01-01
          • 2022-08-12
          • 2010-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多