第3章 psql工具

第 3 章 psql工具

psql 是 PostgreSQL 自带的一个不可或缺的命令行工具,用途广泛,除了执行 SQL 这个基本功能外,还可用于执行脚本、导入导出数据、恢复表数据以及执行其他数据库管理任务,它甚至还可以作为一个简单的报表生成器来使用。

3.1 环境变量

在设置 PGHOSTPGPORTPGUSER 等环境变量后,在调用 psql 命令行时就不用显式地指定主机、端口和用户了,系统会自动使用环境变量设定的值,这一点跟 PostgreSQL 自带的其他命令行工具是一样的。为避免每次登录时都输入密码,你也可以用 PGPASSWORD 这个环境变量来设置登录密码。如果希望以更安全的方式处理登录密码,请使用密码文件。

PSQL_HISTORY
  该变量用于设置 psql 历史日志文件名,该日志中记录了近期通过 psql 执行过的所有命令行,其默认值为~/.psql_history。
PSQLRC
  该变量用于设置用户自定义的配置文件的路径和文件名。用户可以将常用的设置项统一集中存放到自定义配置文件里。

如果你既未设定相应的环境变量,也未在命令行中指定相关参数,那么 psql 会使用系统默认值。

3.2 psql的两种操作模式:交互模式与非交互模式

交互模式中,在 psql 界面上键入 \? 会列出交互模式下支持的所有命令。在 psql 界面上键入\h,后跟命令关键字,则会打印出该命令在 PostgreSQL 官方手册中相应的语法帮助信息。如果希望顺序执行一系列命令,我们建议把这些命令写成一个脚本文件,然后使用 psql 以非交互模式执行该脚本。

在非交互模式下执行脚本文件,只需使用 -f 选项即可:

psql -f some_script_file

在非交互模式下执行 SQL 语句,只需使用 -c 选项即可。如果要一次执行多个语句,语句之间请用分号分隔:

psql -d postgresql_book -c "DROP TABLE IF EXISTS dross; CREATE SCHEMA staging;"

带 psql 交互式命令的脚本

\a ➊
\t
\g create_script.sql
SELECT
'CREATE TABLE staging.factfinder_import (
geo_id varchar(255), geo_id2 varchar(255), geo_display varchar(255),' ||
array_to_string(array_agg('s' ||
lpad(i::text,2,'0') || ' varchar(255),s' ||
lpad(i::text,2,'0') || '_perc varchar(255)'),',') ||
');'
FROM generate_series(1,51) As i;
\o ➋
\i create_script.sql ➌

❶ 我们希望该脚本执行后输出的结果是能直接运行的 SQL 语句,因此需要用 \t(或者 --tuplesonly)选项来忽略标题栏的输出,同时使用 \a 选项关闭对齐模式以防止 psql 为对齐输出结果而自动加上换行符。使用 \g 让所有查询内容都输出到指定文件。
❷ 使用不带参数的 \o 命令来停止查询结果重定向到外部文件。
❸ 使用 \i 加脚本名 create_script.sql 来执行生成的脚本。\i 的效果等同于非交互模式下的 -f 选项。

在操作系统命令行界面下输入以下命令行即可:

psql -f build_stage.psql -d postgresql_book

3.3 定制psql操作环境

psql 在启动阶段会搜索一个名为 psqlrc 的配置文件,如果找到则会顺序执行其中的配置动作,这些配置决定了 psql 的一些行为模式。在 Linux/Unix 环境中,该文件一般会被命名为 .psqlrc 并放置在 postgres 用户的 home 目录下。PostgreSQL 安装完成后找不到此文件是正常的,因为该文件一般需手动创建。该文件中的设置项会覆盖 psql 的默认值。

.psqlrc 文件内容,set 命令后跟的操作内容不允许分为多行书写。使用 set 命令时设置的变量名是区分大小写的。系统变量请使用大写,用户自定义变量请使用小写。

\pset null 'NULL'
\encoding latin1
\set PROMPT1 '%n@%M:%>%x %/# '
\pset pager always
\timing on
\set qstats92 'SELECT usename, datname, left(query,100) || "..." As query FROM pg_stat_activity WHERE state != "idle";'

启动 psql 时,屏幕上会显示该文件中内容被执行后的输出结果。

Null display is "NULL".
Timing is on.
Pager is always used.
psql (9.6beta3)
Type "help" for help.
postgres@localhost:5442 postgresql_book#

如果希望 psql 启动时跳过加载 psqlrc 文件这一步骤,使用默认参数,请添加-X 选项。你可以在 psql 运行时动态修改参数,但必须关闭 psql 再打开才能生效。如果要删除某个 psql 配置变量或者希望将其设置回默认值,可以使用 \unset 命令,后跟变量名称,比如:\unset qstat92。

3.3.1 自定义psql界面提示符

几个元素:登录角色(%n)、主机名(%M)、侦听端口(%>)、事务状态(%x)以及当前使用的 database 名(%/)。

\set PROMPT1 '%n@%M:%>%x %/# '

3.3.2 语句执行时间统计

可通过 \timing 命令来打开或者关闭执行时间统计开关。

SELECT COUNT(*) FROM pg_tables;
count
--------
73
(1 row)
Time: 18.650 ms

3.3.3 事务自动提交

默认情况下,自动提交功能是处于启用状态的,也就是说任何一个 SQL 语句执行完毕后,它所做的数据修改都会被立即提交,这种情况下每个语句都是一个独立的事务,一旦执行完毕其结果就不可撤销。如果你需要运行大量的 DML 语句并且这些语句还未经充分测试,那么自动提交功能会带来大麻烦,此时有必要关闭事务自动提交机制来保护数据。

关闭自动提交功能:

\set AUTOCOMMIT off
UPDATE census.facts SET short_name = 'This is a mistake.';

要回滚事务,请执行:

ROLLBACK;

要提交事务,请执行:

COMMIT;

3.3.4 命令别名

可以使用 \set 来为某个命令创建别名,我们建议你将全局性的别名写到 psqlrc 文件中。

\set eav 'EXPLAIN ANALYZE VERBOSE'

键入 :eav 替代(前面的冒号表示这是一个需要展开的命令变量)。甚至可以为一个完整的查询语句起个别名并存入 psqlrc 文件中。

:eav SELECT COUNT(*) FROM pg_tables;

3.3.5 取出前面执行过的命令行

可以用向上方向键快速找出之前执行过的历史命令。HISTSIZE环境变量决定了系统存储的历史命令行的数量。例如:\set HISTSIZE 10 会将可追溯的历史命令数量设定为最多 10 条。需要将这些语句存入指定的文件中以备后续查看,可以使用 HISTFILE 环境变量来实现此功能。

\set HISTFILE ~/.psql_history - :DBNAME

3.4 psql使用技巧

3.4.1 执行shell命令

psql 中通过 \! 可以直接执行操作系统命令。

3.4.2 用watch命令重复执行语句

它可以实现以固定的频率反复执行某个语句,以便持续观察其输出。例如你需要持续监控系统中当前正在执行的所有语句的情况,那么只需把 watch 语句加到查询语句的后面即可。

SELECT datname, query
FROM pg_stat_activity
WHERE state = 'active' AND pid != pg_backend_pid();
\watch 10

如果需要终止 watch 进程,请执行 CTRL-X 加 CTRL-C。

3.4.3 显示对象信息

使用 \dt+ 命令列出 pg_catalog 中以 pg_t 打头的所有表的信息

\dt+ pg_catalog.pg_t*

使用 \d+ 命令得到对象的详细信息

\d+ pg_ts_dict

3.4.4 行转列视图

更多的行转列示例,请百度查看,太多了。

SELECT student, subject, AVG(score)::numeric(5,2) As avg_score
FROM test_scores
GROUP BY student, subject
ORDER BY student, subject;

\crosstabview student subject avg_score

student 	| algebra 	| calculus 	| chemistry 	| physics 	| scheme
------------+-----------+-----------+---------------+-----------+--------
alex 		| 74.00 	| 73.50 	| 82.00 		| 81.00 	|
leo 		| 82.00 	| 65.50 	| 75.50 		| 72.00 	|
regina 		| 72.50 	| 64.50 	| 73.50 		| 84.00 	| 90.00
sonia 		| 76.50 	| 67.50 	| 84.00 		| 72.00 	|
(4 rows)

\crosstabview 命令应紧跟在你希望实现行转列的 SQL 语句后面。\crosstabview 命令的输入是前面 SQL 语句中查询的三个字段,后面还可以跟一个可选的排序字段。该命令实现的效果是对原生查询结果进行行转列后重排:第一个字段是一行的标记第二个字段被翻转为列第三个字段按照第一个和第二个字段的每种排列组合作为值出现。执行 \crosstabview 命令时也可以不输入字段名,这就要求前面的 SQL 查询语句中只能查询三个字段,命令默认就会去取这三个字段作为入参。

3.4.5 执行动态SQL

可以选择使用 \gexec 命令来执行动态生成的 SQL,其特点是生成 SQL 和执行 SQL 在同一步骤中完成,非常方便。遍历顺序是外层按记录行迭代,内层按字段迭代。gexec 命令还没有支持识别每行记录中的每个字段是否都是一个 SQL,目前仅支持每行是一个SQL 的情况。另外,gexec 仅仅机械地遍历执行所有 SQL,并不关心每个 SQL 的执行结果,即使中途有 SQL 执行出错,gexec 依然会继续遍历执行下去,但它在遍历查找 SQL 的过程中会识别出 null 记录并跳过。

使用 gexec 创建表并插入数据

SELECT
'CREATE TABLE ' || person.name || '( a integer, b integer)' As create,
'INSERT INTO ' || person.name || ' VALUES(1,2) ' AS insert
FROM (VALUES ('leo'),('regina')) AS person (name) \gexec

CREATE TABLE
INSERT 0 1
CREATE TABLE
INSERT 0 1

使用 gexec 获取每张表中的记录数

SELECT
'SELECT ' || quote_literal(table_name) || ' AS table_name,
COUNT(*) As count FROM ' || quote_ident(table_name) AS cnt_q
FROM information_schema.tables
WHERE table_name IN ('leo','regina') \gexec

table_name 	| count
------------+------
leo 		| 1
(1 row)

table_name 	| count
------------+------
regina 		| 1
(1 row)

3.5 使用psql实现数据的导入和导出

psql 支持一个叫作 \copy 的命令,该命令可以将数据导出到文本文件中,也可以从文本文件中导入数据。文本文件中默认使用制表符作为分隔符,当然你也可以指定使用其他分隔符。文本中必须使用换行符来分隔不同的行,否则无法正确区分两行记录。

3.5.1 使用psql进行数据导入

psql 把整个导入过程当成一个完整的事务来处理,因此如果导入数据时遇到任何错误,那么整个导入动作所做的修改会完全回滚掉。如果你对源文件中数据的特点并不完全了解,我们建议你用最宽松的条件来创建容纳表,等数据导入之后再对数据进行细化加工。

使用 psql 导入数据

\connect postgresql_book
\cd /postgresql_book/ch03
\copy staging.factfinder_import FROM DEC_10_SF1_QTH1_with_ann.csv CSV

首先连接数据库,然后使用 \cd 切换到含有数据源文件的目录,最后执行 \copy 导入动作。因为 \copy 命令支持的默认分隔符是制表符,所以我们必须在命令行中额外指明源文件是用逗号作为分隔符的 CSV 格式。

如果源文件使用了一些非标准的分隔符,比如竖杠(|),那么也请在命令中以如下方式指明:

\copy sometable FROM somefile.txt DELIMITER '|';

如果希望把文本中的空值替换为你指定的内容再导入,可以用 NULL AS 来标记要替换的内容:

\copy sometable FROM somefile.txt NULL As '';

注意
请不要将 psql 中的 \copy 命令与 SQL 语言提供的 COPY 语句相混淆。psql 是一个客户端工具,所有路径都是相对于已连接客户端进行解释的。而 SQL copy 是基于服务器的,并在 postgres 服务操作系统账户的环境下运行。因此输入文件必须驻留在可由 postgres 服务账户访问的路径中。

3.5.2 使用psql进行数据导出

使用 psql 导出数据,默认情况下 psql 导出数据时会使用 tab 键作为分隔符。然而,以这种格式导出时默认不导出标题行。你可以通过指定 HEADER 选项来要求导出标题行,请注意该选项仅当输出格式为 CSV 时才可使用。

\connect postgresql_book
\copy (SELECT * FROM staging.factfinder_import WHERE s01 ~ E'^[0-9]+' )
TO '/test.tab'
WITH DELIMITER E'\t' CSV HEADER

使用 psql 导出数据,FORCE QUOTE * 表示输出的所有列的前后都将加上引用符,这个引用符默认就是双引号,但为清晰起见,我们还是显式指定了一下。

\connect postgresql_book
\copy staging.factfinder_import TO '/test.csv'
WITH CSV HEADER QUOTE '"' FORCE QUOTE *

3.5.3 从外部程序复制数据以及将数据复制到外部程序

psql 开始支持从命令行程序的输出中获取数据并将数据转储到表中,这类命令行程序包括 curl、ls 和 wget 等。(从标准输出接收数据导入到存储表中

使用 psql 导入某个目录下的文件列表

\connect postgresql_book
CREATE TABLE dir_list (filename text);
\copy dir_list FROM PROGRAM 'dir C:\projects /b'

3.6 使用psql制作简单的报表

利用 psql 制作简单的 HTML 报表。

postgres=# SELECT category, count(*) As num_per_cat
postgres-# FROM pg_settings
postgres-# WHERE category LIKE '%Query%'
postgres-# GROUP BY category
postgres-# ORDER BY category;

                     category                      | num_per_cat 
---------------------------------------------------+-------------
 Query Tuning / Genetic Query Optimizer            |           7
 Query Tuning / Other Planner Options              |           7
 Query Tuning / Planner Cost Constants             |          13
 Query Tuning / Planner Method Configuration       |          17
 Statistics / Query and Index Statistics Collector |           5
(5 rows)

编写 settings_report.psql 文件来设置报表内容。

\o settings_report.html ➊
\T 'cellspacing=0 cellpadding=0' ➋
\qecho '' ➌
\qecho 'PostgreSQL Settings'
\qecho '

Planner Settings

' \x on ➍ \t on ➎ \pset format html ➏ SELECT category, string_agg(name || '=' || setting, E'\n' ORDER BY name) As settings ➐ FROM pg_settings WHERE category LIKE '%Planner%' GROUP BY category ORDER BY category; \H \qecho '

File Locations

' \x off ➑ \t on \pset format html SELECT name, setting FROM pg_settings WHERE category = 'File Locations' ORDER BY name; \qecho '

Memory Settings

'
SELECT name, setting, unit FROM pg_settings WHERE category ILIKE '%memory%' ORDER BY name; \qecho '
'
\qecho '' \o

❶ 指定查询结果输出到一个文件中。
❷ HTML 表格的输出格式设置。
❸ 添加一些附加的 HTML 代码。
❹ 打开记录输出的展开模式。重复每一个记录的列标题,并将每一个记录的每一列作为一个单独的记录输出。
❺ 强制查询的结果输出为一个 HTML 表格。
❻ string_agg() 是 PostgreSQL 9.0 中引入的一个函数,可以将聚合运算中被划为同组的字符串值合并为单个字符串。
❼ 关闭记录输出的展开模式,这样第二个和第三个查询结果在报表上的输出格式应该是每条记录仅占一行。
❽ 设置“是否仅输出记录”开关。如果此开关是开启的,则会忽略列标题和行计数。

可以使用 psql 以交互方式连接并执行 \i settings_report.psql,也可以在操作系统的命令行界面上运行 psql -f settings_report.psql 。生成结果:

<html><head><style>H2{color:maroon}style>
<title>PostgreSQL Settingstitle>head><body>
<table><tr valign='top'><td><h2>Planner Settingsh2>
<table border="1" cellspacing=0 cellpadding=0>
  <tr><td colspan="2"> td>tr>
  <tr valign="top">
    <th>categoryth>
    <td align="left">Query Tuning / Other Planner Optionstd>
  tr>
  <tr valign="top">
    <th>settingsth>
    <td align="left">constraint_exclusion=partition<br />
cursor_tuple_fraction=0.1<br />
default_statistics_target=100<br />
force_parallel_mode=off<br />
from_collapse_limit=8<br />
jit=off<br />
join_collapse_limit=8td>
  tr>
  <tr><td colspan="2"> td>tr>
  <tr valign="top">
    <th>categoryth>
    <td align="left">Query Tuning / Planner Cost Constantstd>
  tr>
  <tr valign="top">
    <th>settingsth>
    <td align="left">cpu_index_tuple_cost=0.005<br />
cpu_operator_cost=0.0025<br />
cpu_tuple_cost=0.01<br />
effective_cache_size=178560<br />
jit_above_cost=100000<br />
jit_inline_above_cost=500000<br />
jit_optimize_above_cost=500000<br />
min_parallel_index_scan_size=64<br />
min_parallel_table_scan_size=1024<br />
parallel_setup_cost=0<br />
parallel_tuple_cost=0<br />
random_page_cost=4<br />
seq_page_cost=1td>
  tr>
  <tr><td colspan="2"> td>tr>
  <tr valign="top">
    <th>categoryth>
    <td align="left">Query Tuning / Planner Method Configurationtd>
  tr>
  <tr valign="top">
    <th>settingsth>
    <td align="left">enable_bitmapscan=on<br />
enable_gathermerge=on<br />
enable_hashagg=on<br />
enable_hashjoin=on<br />
enable_indexonlyscan=on<br />
enable_indexscan=on<br />
enable_material=on<br />
enable_mergejoin=on<br />
enable_nestloop=on<br />
enable_parallel_append=on<br />
enable_parallel_hash=on<br />
enable_partition_pruning=on<br />
enable_partitionwise_aggregate=off<br />
enable_partitionwise_join=off<br />
enable_seqscan=on<br />
enable_sort=on<br />
enable_tidscan=ontd>
  tr>
table>
td><td><h2>File Locationsh2>
<table border="1" cellspacing=0 cellpadding=0>
  <tr valign="top">
    <td align="left">config_filetd>
    <td align="left">/pgsql/10/data/postgresql.conftd>
  tr>
  <tr valign="top">
    <td align="left">data_directorytd>
    <td align="left">/pgsql/10/datatd>
  tr>
  <tr valign="top">
    <td align="left">external_pid_filetd>
    <td align="left">  td>
  tr>
  <tr valign="top">
    <td align="left">hba_filetd>
    <td align="left">/pgsql/10/data/pg_hba.conftd>
  tr>
  <tr valign="top">
    <td align="left">ident_filetd>
    <td align="left">/pgsql/10/data/pg_ident.conftd>
  tr>
table>
<h2>Memory Settingsh2>
<table border="1" cellspacing=0 cellpadding=0>
  <tr valign="top">
    <td align="left">autovacuum_work_memtd>
    <td align="left">-1td>
    <td align="left">kBtd>
  tr>
  <tr valign="top">
    <td align="left">dynamic_shared_memory_typetd>
    <td align="left">posixtd>
    <td align="left">  td>
  tr>
  <tr valign="top">
    <td align="left">huge_pagestd>
    <td align="left">trytd>
    <td align="left">  td>
  tr>
  <tr valign="top">
    <td align="left">maintenance_work_memtd>
    <td align="left">1048576td>
    <td align="left">kBtd>
  tr>
  <tr valign="top">
    <td align="left">max_prepared_transactionstd>
    <td align="left">0td>
    <td align="left">  td>
  tr>
  <tr valign="top">
    <td align="left">max_stack_depthtd>
    <td align="left">2048td>
    <td align="left">kBtd>
  tr>
  <tr valign="top">
    <td align="left">shared_bufferstd>
    <td align="left">59520td>
    <td align="left">8kBtd>
  tr>
  <tr valign="top">
    <td align="left">temp_bufferstd>
    <td align="left">1024td>
    <td align="left">8kBtd>
  tr>
  <tr valign="top">
    <td align="left">track_activity_query_sizetd>
    <td align="left">1024td>
    <td align="left">Btd>
  tr>
  <tr valign="top">
    <td align="left">work_memtd>
    <td align="left">8192td>
    <td align="left">kBtd>
  tr>
table>
td>tr>table>
body>html>

用浏览器打开 html 文件:

PostgreSQL Settings

Planner Settings

 
category Query Tuning / Other Planner Options
settings constraint_exclusion=partition
cursor_tuple_fraction=0.1
default_statistics_target=100
force_parallel_mode=off
from_collapse_limit=8
jit=off
join_collapse_limit=8
 
category Query Tuning / Planner Cost Constants
settings cpu_index_tuple_cost=0.005
cpu_operator_cost=0.0025
cpu_tuple_cost=0.01
effective_cache_size=178560
jit_above_cost=100000
jit_inline_above_cost=500000
jit_optimize_above_cost=500000
min_parallel_index_scan_size=64
min_parallel_table_scan_size=1024
parallel_setup_cost=0
parallel_tuple_cost=0
random_page_cost=4
seq_page_cost=1
 
category Query Tuning / Planner Method Configuration
settings enable_bitmapscan=on
enable_gathermerge=on
enable_hashagg=on
enable_hashjoin=on
enable_indexonlyscan=on
enable_indexscan=on
enable_material=on
enable_mergejoin=on
enable_nestloop=on
enable_parallel_append=on
enable_parallel_hash=on
enable_partition_pruning=on
enable_partitionwise_aggregate=off
enable_partitionwise_join=off
enable_seqscan=on
enable_sort=on
enable_tidscan=on

File Locations

config_file /pgsql/10/data/postgresql.conf
data_directory /pgsql/10/data
external_pid_file  
hba_file /pgsql/10/data/pg_hba.conf
ident_file /pgsql/10/data/pg_ident.conf

Memory Settings

autovacuum_work_mem -1 kB
dynamic_shared_memory_type posix  
huge_pages try  
maintenance_work_mem 1048576 kB
max_prepared_transactions 0  
max_stack_depth 2048 kB
shared_buffers 59520 8kB
temp_buffers 1024 8kB
track_activity_query_size 1024 B
work_mem 8192 kB

第 4 章 pgAdmin的使用

(初级学者特别适合)略…

你可能感兴趣的:(Postgresql即学即用)