【问题标题】:How to dynamically pass psql variable value at runtime?如何在运行时动态传递 psql 变量值?
【发布时间】:2019-12-30 07:26:04
【问题描述】:

我正在尝试在 psql 中为 DBA/管理员创建快捷方式。
我创建了一些函数和查询,它们为我提供了诸如架构大小(以字节为单位)或按使用存储顺序排列的表列表等信息。每当管理员或 DBA 想要获取有关数据库的一些信息时,都会使用这些信息。
我可以使用 select 或作为 get_size() 之类的函数自然地运行这些查询,但我希望它们可以作为快捷方式访问,类似于本机反斜杠命令(\dx、\dt 等)。
所以我使用了 psql 的 \set 功能将查询/函数存储为变量,我将它们放入 psqlrc 文件中:
\set size 'select pg_size_pretty(my_size_function(''public''));'
然后,当我在 psql 中键入 :size 时,我会得到“公共”模式的大小。
我想要的是能够动态传递模式名称,所以我可以运行类似的东西 :size public, :size schema2
我尝试将\set 更改为:\set size 'select pg_size_pretty(my_size_function(:schema));',但我只能通过先执行\set schema '''public''' 来调用它。
由于重点是将这些普遍用作快捷方式,因此每次都必须手动运行\set 命令会达不到目的。 在 Oracle 中,冒号是一个绑定变量,将在运行时读取。 如何使用 psql 做到这一点?

【问题讨论】:

    标签: postgresql psql


    【解决方案1】:

    我使用这些方式。

    1. Postgres Functions(在 Postgres CLI 中)

      postgres=# CREATE OR REPLACE FUNCTION getSize(tableName varchar) RETURNS varchar LANGUAGE SQL as
      postgres-# $$
      postgres$#     SELECT pg_size_pretty(pg_relation_size(tableName));
      postgres$# $$;
      CREATE FUNCTION
      
      postgres=# select getSize('test');
        getsize
      ------------
       8192 bytes
      (1 row)
      
    2. 从 Shell(Postgres CLI 外部)

      • psqlgettablesize(schema, tablename) - 获取表格大小。传递all 作为架构参数以获取所有架构。

        $ psqlgettablesize customer events
                table_name        |     total_size      | table_size  |  index_size
        --------------------------+---------------------+-------------+---------------
         test(complete database)  | 19039892127 (18 GB) |             |
         ---------                | ---------           | ---------   | ---------
         customer.events          | 24576 (24 kB)       | 0 (0 bytes) | 24576 (24 kB)
        (3 rows)
        
      • psqlgettablecount(schema, tablename) - 获取表中的行数,在模式中

        $ psqlgettablecount customer events
          count
        ----------
         51850000
        (1 row)
        
      • psqlgetvacuumdetails(schema, tablename) - 在模式中获取表的真空详细信息

        $ psqlgetvacuumdetails customer events
         schemaname |  relname  | n_live_tup | n_dead_tup |        last_analyze        | analyze_count |      last_autoanalyze      | autoanalyze_count |        last_vacuum        | vacuum_count | last_autovacuum | autovacuum_count
        ------------+-----------+------------+------------+----------------------------+---------------+----------------------------+-------------------+---------------------------+--------------+-----------------+------------------
         customer   |   events  |          0 |          0 | 2019-12-02 18:25:04.887653 |             2 | 2019-11-27 18:49:19.002405 |                 1 | 2019-11-29 13:11:15.92002 |            1 |                 |                0
        (1 row)
        
      • psqltruncatetable(schema, tablename) - 授权后截断架构中的表。

        $ psqltruncatetable customer events
        Are you sure to truncate table 'customer.events' (y/n)? y
        Time: 4.944 ms
        
      • psqlsettings(category) - 获取 Postgres 的设置

        $ psqlsettings Autovacuum
                        name                 |  setting  | unit |  category  |                                        short_desc                                         | extra_desc |  context   | vartype | source  | min_val |  max_val   | enumvals | boot_val  | reset_val | sourcefile | sourceline | pending_restart
        -------------------------------------+-----------+------+------------+-------------------------------------------------------------------------------------------+------------+------------+---------+---------+---------+------------+----------+-----------+-----------+------------+------------+-----------------
         autovacuum                          | on        |      | Autovacuum | Starts the autovacuum subprocess.                                                         |            | sighup     | bool    | default |         |            |          | on        | on        |            |            | f
         autovacuum_analyze_scale_factor     | 0.1       |      | Autovacuum | Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples. |            | sighup     | real    | default | 0       | 100        |          | 0.1       | 0.1       |            |            | f
        
      • psqlselectrows(schema, tablename) - 从表中获取行,在模式中

        $ psqlselectrows customer events
         id | name
        ----+------
          1 | Clicked
          2 | Page Loaded
        (10 rows)
        

    #Colors
    B_BLACK='\033[1;30m'
    B_RED='\033[1;31m'
    B_GREEN='\033[1;32m'
    B_YELLOW='\033[1;33m'
    B_BLUE='\033[1;34m'
    B_PURPLE='\033[1;35m'
    B_CYAN='\033[1;36m'
    B_WHITE='\033[1;37m'
    RESET='\033[0m'
    
    #Postgres Command With Params
    psqlcommand="$POSTGRES_BIN/psql -U postgres test -q -c"
    
    function psqlgettablesize()
    {
        [ -z "$1" ] && echo -e "${B_RED}Argument 1 missing. Schema name needed. ${B_YELLOW}(Pass 'all' to get details from all schema(s)${RESET}" ||
        {
            criteria="and table_schema = '$1'"
            if [ "$1" == "all" ]; then
                criteria=""
            fi
    
            if [ "$2" != "" ]; then
                criteria+=" and table_name = '$2'"
            fi
    
            [ -z "$2" ] && echo -e "${B_YELLOW}Table name not given. ${B_GREEN}Showing size of all tables in $1 schema(s)${RESET}"
            query="SELECT
                concat(current_database(), '(complete database)') AS table_name, concat(pg_database_size(current_database()), ' (', pg_size_pretty(pg_database_size(current_database())), ')') AS total_size, '' AS table_size, '' AS index_size
            UNION ALL SELECT '---------','---------','---------','---------'
            UNION ALL SELECT
                table_name,
                concat(total_table_size, ' (', pg_size_pretty(total_table_size), ')'),
                concat(table_size, ' (', pg_size_pretty(table_size), ')'),
                concat(index_size, ' (', pg_size_pretty(index_size), ')')
            FROM (
                SELECT
                    concat(table_schema, '.', table_name) AS table_name,
                    pg_total_relation_size(concat(table_schema, '.', table_name)) AS total_table_size,
                    pg_relation_size(concat(table_schema, '.', table_name)) AS table_size,
                    pg_indexes_size(concat(table_schema, '.', table_name)) AS index_size
                FROM information_schema.tables where table_schema !~ '^pg_' AND table_schema <> 'information_schema' $criteria ORDER BY total_table_size) AS sizes";
            $psqlcommand "$query"
        }
    }
    function psqlgettablecount()
    {
        [ -z "$1" ] && echo -e "${B_RED}Argument 1 missing: Need schema name${RESET}"
        [ -z "$2" ] && echo -e "${B_RED}Argument 2 missing: Need table name${RESET}" ||
        $psqlcommand "select count(*) from $1.$2;"
    }
    function psqlgetvacuumdetails()
    {
        [ -z "$1" ] && echo -e "${B_RED}Argument 1 missing: Need schema name${RESET}" ||
        [ -z "$2" ] && echo -e "${B_RED}Argument 2 missing: Need table name${RESET}" ||
        $psqlcommand "SELECT schemaname, relname, n_live_tup, n_dead_tup, last_analyze::timestamp, analyze_count, last_autoanalyze::timestamp, autoanalyze_count, last_vacuum::timestamp, vacuum_count, last_autovacuum::timestamp, autovacuum_count FROM pg_stat_user_tables where schemaname = '$1' and relname='$2';"
    }
    function psqltruncatetable()
    {
        [ -z "$1" ] && echo -e "${B_RED}Argument 1 missing: Need schema name${RESET}" ||
        [ -z "$2" ] && echo -e "${B_RED}Argument 2 missing: Need table name${RESET}" ||
        {
            read -p "$(echo -e ${B_YELLOW}"Are you sure to truncate table '$1.$2' (y/n)? "${RESET})" choice
            case "$choice" in
                y|Y ) $psqlcommand "TRUNCATE $1.$2;";;
                n|N ) echo -e "${B_GREEN}Table '$1.$2' not truncated${RESET}";;
                * ) echo -e "${B_RED}Invalid option${RESET}";;
            esac
        }
    }
    function psqlsettings()
    {
        query="select * from pg_settings"
        if [ "$1" != "" ]; then
            query="$query where category like '%$1%'"
        fi
        query="$query ;"
        $psqlcommand "$query"
        if [ -z "$1" ]; then
            echo -e "${B_YELLOW}Passing Category as first argument will filter the related settings.${RESET}"
        fi
    }
    function psqlselectrows()
    {
        [ -z "$1" ] && echo -e "${B_RED}Argument 1 missing: Need schema name${RESET}" ||
        [ -z "$2" ] && echo -e "${B_RED}Argument 2 missing: Need table name${RESET}" ||
        $psqlcommand "SELECT * from $1.$2"
    }
    

    【讨论】:

    • 这个想法是在 psql 中,用户不必输入任何 sql,只需像\dx 这样的快捷方式。 bash 解决方案更好,但我需要可以在 psql 本身中运行的东西。使用 psql \set 命令来别名 bash 命令的混合解决方案可能很好,例如\set get_table_size '\! psqlgettablesize(:schema,:table),但归结为无法动态输入 :schema 或 :table 而不先设置它。所以最好完全留在 psql 中而不调用 bash,就像我的回答一样。
    【解决方案2】:

    我不知道如何动态传递变量,所以我选择了一个别名和变量系统,它们协同工作以提供我正在寻找的东西。所以我可以运行:load_schema &lt;schemaname&gt;,然后运行与“加载”模式交互的命令。加载模式只是给 \set 命令起别名。这样,不熟悉 psql 的人只需按 :,选项卡自动完成就会向他们显示我所有的快捷方式。
    我所有的代码都是here
    这不是我想要的,所以我不会接受它,但它足够接近以防万一其他人想要这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 2021-03-18
      • 2018-07-15
      • 1970-01-01
      相关资源
      最近更新 更多