\a 在非对齐和对齐的输出模式之间切换
\C [字串] 设置表标题,如果参数空则取消标题
\cd [目录名] 改变当前的工作目录
\copy ... 执行 sql COPY,数据流指向客户端主机
\copyright 显示 Postgresql 用法和发布信息
\d [名字] 描述表,索引,序列,或者视图
列出表/索引/序列/视图/系统表
\d{t|i|s|v|S} [模式] (加 "+" 获取更多信息)
列出表/索引/序列/视图/系统表
\da [模式] 列出聚集函数
\dd [模式] 显示目标的注释
\dD [模式] 列出域
\df [模式] 列出函数 (加 "+" 获取更多的信息)
\do [名字] 列出操作符
\dl 列出大对象,和 \lo_list 一样
\dp [模式] 列出表访问权限
\dT [模式] 列出数据类型 (加 "+" 获取更多的信息)
\du [模式] 列出用户
\e [文件名] 用一个外部编辑器编辑当前查询缓冲区或者文件
\echo [字串] 向标准输出写出文本
\encoding [哪种编码] 设置客户端编码(EUC_JP,GBK)
\f [字串] 设置域分隔符
\g 文件名 向服务器发送 sql 命令 (并且把结果写到文件或者 |管道)
\h [名字] sql 命令的语法帮助,用 * 可以看所有命令的帮助
\H 在 HTML 输出模式之间切换 (当前是 关闭)
\i 文件名 执行来自文件的命令
\l 列出所有数据库
\lo_export,\lo_import,\lo_list,\lo_unlink
大对象操作
\o 文件名 向文件或者 |管道 发送所有查询结果
\p 显示当前查询缓冲区的内容
\pset 名字 [值] 设置表的输出选项 (NAME := {foramt|border|expaned|
(名字 := {foramt|border|expanded|fieldsep|null|recordsep|
tuples_only|title|tableattr|pager})
\q 退出 psql
\r 重置 (清理) 查询缓冲区
\s [文件名] 打印历史或者将其保存到文件
\set [名字 [值]] 设置内部变量,如果没有参数就列出所有
\t 只显示行 (当前是 关闭)
\T [字串] 设置 HTML <表>标记属性,如果没有参数就取消设置
\timing 查询计时开关切换 (目前是 关闭)
\unset 名字 取消(删除)内部变量
\w [文件名] 将当前查询缓冲区写出到文件
\x 在扩展输出之间切换 (目前是 关闭)
\z [模式] 列出表访问权限 (和 \dp 一样)
\! [命令] 在 shell 里执行命令或者开始一个交互的 shell
\echo [string] 输出字符串
命令:
\copy 表名 to 文件名|标准输出 [delimiter as ‘分隔符’] [null as ‘null表示的字符串’ ] [csv quote as ‘引号的类型’]
解释:
delimiter as ‘分隔符’ :说明输出设备的文本中表的每个字段用什么字符分割,默认是tab;
null as ‘null表示的字符串’:说明输出设备的文本中表的NULL值的表示方法,默认为“\N”;
csv quote as ‘引号类型’ :说明导出的csv文件中的引号类型是什么,
对于Postgres7.4以前的版本,不支持csv的导入与导出,这时不要使用这个可选项。
例子:
aa=#\copy testtable to data.csv delimiter as ‘,’ csv quote as ‘”‘
这条命令将testtable表中的内容作为sql语句,导出data.csv文件中。
delimiter as ‘,’ :说明data.txt文本中表的每个字段用“逗号”分割;
csv quote as ‘”‘ :说明csv中的引号类型是“双引号”。
像前面说的:这个例子不适用在Postgres7.4以前的版本。
注意文件保存路径默认在:
C:\Documents and Settings\zhuyaopeng\目录下 而且只保存数据,不保存表结构
命令:
\copy 表名 form 文件名|标准输入 [delimiter as ‘分隔符’] [null as ‘null表示的字符串’ ] [csv quote as ‘引号的类型’]
例子:
aa=#\copy testtable from data.csv delimiter as ‘,’ csv quote as ‘”‘
这条命令将data.csv文件中的文本,作为sql语句导入到testtable表,
delimiter as ‘,’ :说明data.txt文本中表的每个字段用“逗号”分割;
csv quote as ‘”‘ :说明csv中的引号类型是“双引号”。
如果你只是要提取几行数据,并且你在执行查询中知道确切的行数,你可以使用LIMIT功能。如果有一个索引与 ORDER BY中的条件匹配,Postgresql 可能就只处理要求的头几条记录,(否则将对整个查询进行处理直到生成需要的行)。如果在执行查询功能时不知道确切的记录数,可使用游标(cursor)和FETCH功能。
SELECT cols
FROM tab
ORDER BY random()
LIMIT 1 ;
6.如何查看表、索引、数据库以及用户的定义?如何查看psql里用到的查询指令并显示它们?
在psql中使用 \dt 命令来显示数据表的定义,要了解psql中的完整命令列表可使用\? ,另外,你也可以阅读 psql 的源代码文件pgsql/src/bin/psql/describe.c,它包括为生成psql反斜杠命令的输出的所有 sql 命令。你还可以带 -E 选项启动 psql,这样它将打印出执行你在psql中所给出的命令的内部实际使用的SQL查询。Postgresql也提供了一个兼容sql的INFORMATION SCHEMA接口, 你可以从这里获取关于数据库的信息。
在系统中有一些以pg_ 打头的系统表也描述了表的定义。
也可以浏览一下 pgsql/src/tutorial/syscat.source文件,它列举了很多可从数据库系统表中获取信息的SELECT语法。
7.如何更改一个字段的数据类型?
在8.0版本里更改一个字段的数据类型很容易,可使用 ALTER TABLE ALTER COLUMN TYPE 。
在以前的版本中,可以这样做:
BEGIN;
ALTER TABLE tab ADD COLUMN new_col new_data_type;
UPDATE tab SET new_col = CAST(old_col AS new_data_type);
ALTER TABLE tab DROP COLUMN old_col;
COMMIT;
你然后可以使用VACUUM FULL tab 指令来使系统收回无效数据所占用的空间。
8.一行记录,一个表,一个库的最大尺寸是多少?
下面是一些限制:
一个数据库最大尺寸? 无限制(已存在有 32TB 的数据库)
一个表的最大尺寸? 32 TB
一行记录的最大尺寸? 1.6 TB
一个字段的最大尺寸? 1 GB
一个表里最大行数? 无限制
一个表里最大列数? 250-1600 (与列类型有关)
一个表里的最大索引数量? 无限制
当然,实际上没有真正的无限制,还是要受可用磁盘空间、可用内存/交换区的制约。事实上,当这些数值变得异常地大时,系统性能也会受很大影响。
表的最大尺寸 32 TB 不需要操作系统对大文件的支持。大表用多个 1 GB 的文件存储,因此文件系统尺寸的限制是不重要的。
如果缺省的块大小增长到 32K ,最大的表尺寸和最大列数还可以增加到四倍。
9.存储一个典型的文本文件里的数据需要多少磁盘空间?
一个 Postgres 数据库(存储一个文本文件)所占用的空间最多可能需要相当于这个文本文件自身大小5倍的磁盘空间。
例如,假设有一个 100,000 行的文件,每行有一个整数和一个文本描述。假设文本串的平均长度为20字节。文本文件占用 2.8 MB。存放这些数据的 Postgresql 数据库文件大约是 6.4 MB:
32 字节: 每行的头(估计值)
24 字节: 一个整数型字段和一个文本型字段
+ 4 字节: 页面内指向元组的指针
----------------------------------------
60 字节每行
Postgresql 数据页的大小是 8192 字节 (8 KB),则:
8192 字节每页
------------------- = 136 行/数据页(向下取整)
60 字节每行
100000 数据行
-------------------- = 735 数据页(向上取整)
128 行每页
735 数据页 * 8192 字节/页 = 6,021,120 字节(6 MB)
索引不需要这么多的额外消耗,但也确实包括被索引的数据,因此它们也可能很大。
空值NULL存放在位图中,因此占用很少的空间。
并非每个查询都会自动使用索引。只有在表的大小超过一个最小值,并且查询只会选中表中较小比例的记录时才会采用索引。这是因为索引扫描引起的随即磁盘存取可能比直接地读取表(顺序扫描)更慢。
为了判断是否使用索引,Postgresql必须获得有关表的统计值。这些统计值可以使用 VACUUM ANALYZE,或 ANALYZE 获得。使用统计值,优化器知道表中有多少行,就能够更好地判断是否利用索引。统计值对确定优化的连接顺序和连接方法也很有用。在表的内容发生变化时,应定期进行统计值的更新收集。
索引通常不用于 ORDER BY 或执行连接。对一个大表的一次顺序扫描,再做一个显式的排序通常比索引扫描要快。
但是,在 LIMIT 和 ORDER BY 结合使用时经常会使用索引,因为这只会返回表的一小部分。 实际上,虽然 MAX() 和 MIN() 并不使用索引,通过对 ORDER BY 和 LLIMIT 使用索引取得最大值和最小值也是可以的:
SELECT col
FROM tab
ORDER BY col [ DESC ]
LIMIT 1;
如果你确信Postgresql的优化器使用顺序扫描是不正确的,你可以使用SET enable_seqscan TO 'off'指令,然后再次运行查询,你就可以看出使用一个索引扫描是否确实要快一些。
当使用通配符操作,例如 LIKE 或 ~ 时,索引只能在特定的情况下使用:
字符串的开始部分必须是普通字符串,也就是说:
LIKE 模式不能以 % 打头。
~ (正则表达式)模式必须以 ^ 打头。
字符串不能以匹配多个字符的模式类打头,例如 [a-e]。
大小写无关的查找,如 ILIKE 和 ~* 等不使用索引,但可以用 4.8 节描述的函数索引。
在做 initdb 时必须采用缺省的本地设置 C locale,因为系统不可能知道在非C locale情况时下一个最大字符是什么。在这种情况下,你可以创建一个特殊的text_pattern_ops索引来用于LIKE的索引。
在8.0之前的版本中,除非要查询的数据类型和索引的数据类型相匹配,否则索引经常是未被用到,特别是对int2,int8和数值型的索引。
11.我怎样做正则表达式搜索和大小写无关的正则表达式查找?怎样利用索引进行大小写无关查找?
操作符 ~ 处理正则表达式匹配,而 ~* 处理大小写无关的正则表达式匹配。大写些无关的 LIKE 变种成为 ILIKE。
大小写无关的等式比较通常写做:
SELECT *
FROM tab
WHERE lower(col) = 'abc';
这样将不会使用标准的索引。但是可以创建一个可被利用的函数索引:
CREATE INDEX tabindex ON tab (lower(col));
12.在一个查询里,我怎样检测一个字段是否为 NULL ?我如何才能准确排序而不论某字段是否含 NULL 值?
用 IS NULL 和 IS NOT NULL 测试这个字段,具体方法如下:
SELECT *
FROM tab
WHERE col IS NULL;
为了能对含 NULL字段排序,可在 ORDER BY 条件中使用 IS NULL和 IS NOT NULL 修饰符,条件为真 true 将比条件为假false 排在前面,下面的例子就会将含 NULL 的记录排在结果的上面部分:
SELECT *
FROM tab
ORDER BY (col IS NOT NULL)
13.各种字符类型之间有什么不同?
类型 内部名称 说明
VARCHAR(n) varchar 指定了最大长度,变长字符串,不足定义长度的部分不补齐
CHAR(n) bpchar 定长字符串,实际数据不足定义长度时,以空格补齐
TEXT text 没有特别的上限限制(仅受行的最大长度限制)
BYTEA bytea 变长字节序列(使用NULL也是允许的)
"char" char 一个字符
上面所列的前四种类型是"varlena"(变长)类型(也就是说,开头的四个字节是长度,后面才是数据)。于是实际占用的空间比声明的大小要多一些。然而这些类型都可以被压缩存储,也可以用 TOAST 脱机存储,因此磁盘空间也可能比预想的要少。
VARCHAR(n) 在存储限制了最大长度的变长字符串是最好的。 TEXT 适用于存储最大可达 1G左右但未定义限制长度的字符串。
CHAR(n) 最适合于存储长度相同的字符串。 CHAR(n)会根据所给定的字段长度以空格补足(不足的字段内容), 而 VARCHAR(n) 只存储所给定的数据内容。 BYTEA 用于存储二进制数据,尤其是包含 NULL 字节的值。这些类型具有相似的性能特性。
14.我如何获得一个插入的序列号的值?
一种方法是在插入之前先用函数 nextval() 从序列对象里检索出下一个 SERIAL 值,然后再显式插入。使用 4.11.1 里的例表,可用伪码这样描述:
new_id = execute("SELECT nextval('person_id_seq')");
execute("INSERT INTO person (id,name) VALUES (new_id,'Blaise Pascal')");
这样还能在其他查询中使用存放在 new_id 里的新值(例如,作为 person 表的外键)。 注意自动创建的 SEQUENCE 对象的名称将会是 <table>_<serialcolumn>_seq, 这里 table 和 serialcolumn 分别是你的表的名称和你的 SERIAL 字段的名称。
类似的,在 SERIAL 对象缺省插入后你可以用函数 currval() 检索刚赋值的 SERIAL 值,例如:
execute("INSERT INTO person (name) VALUES ('Blaise Pascal')");
new_id = execute("SELECT currval('person_id_seq')");
15.使用 currval() 会导致和其他用户的冲突情况(race condition)吗?
不会。currval() 返回的是你本次会话进程所赋的值而不是所有用户的当前值。
16.为什么不在事务异常中止后重用序列号呢?为什么在序列号字段的取值中存在间断呢?
为了提高并发性,序列号在需要的时候赋予正在运行的事务,并且在事务结束之前不进行锁定,这就会导致异常中止的事务后,序列号会出现间隔。
17.什么是 OID ?什么是 CTID ?
Postgresql 里创建的每一行记录都会获得一个唯一的OID,除非在创建表时使用WITHOUT OIDS选项。 OID创建时会自动生成一个4字节的整数,所有 OID 在整个 Postgresql 中均是唯一的。 然而,它在超过40亿时将溢出, OID此后会出现重复。Postgresql 在它的内部系统表里使用 OID 在表之间建立联系。
在用户的数据表中,最好是使用SERIAl来代替OID 因为SERIAL只是保证在单个表中数据是唯一的,这样它溢出的可能性就非常小了, SERIAL8可用来保存8字节的序列号字段。
CTID 用于标识带着数据块(地址)和(块内)偏移的特定的物理行。 CTID 在记录被更改或重载后发生改变。索引入口使用它们指向物理行。
18.为什么我收到错误信息“ERROR: Memory exhausted in AllocSetAlloc()”?
这很可能是系统的虚拟内存用光了,或者内核对某些资源有较低的限制值。在启动 postmaster 之前试试下面的命令:
ulimit -d 262144
limit datasize 256m
取决于你用的 shell,上面命令只有一条能成功,但是它将把你的进程数据段限制设得比较高,因而也许能让查询完成。这条命令应用于当前进程,以及所有在这条命令运行后创建的子进程。如果你是在运行sql客户端时因为后台返回了太多的数据而出现问题,请在运行客户端之前执行上述命令。
19.怎样进行 outer join (外连接)?
Postgresql 采用标准的 sql 语法支持外连接。这里是两个例子:
SELECT *
FROM t1 LEFT OUTER JOIN t2 ON (t1.col = t2.col);
或是
SELECT *
FROM t1 LEFT OUTER JOIN t2 USING (col);
这两个等价的查询在 t1.col 和 t2.col 上做连接,并且返回 t1 中所有未连接的行(那些在 t2 中没有匹配的行)。 右[外]连接(RIGHT OUTER JOIN)将返回 t2 中未连接的行。 完全外连接(FULL OUTER JOIN)将返回 t1 和 t2 中未连接的行。 关键字 OUTER 在左[外]连接、右[外]连接和完全[外]连接中是可选的,普通连接被称为内连接(INNER JOIN)。
没有办法查询当前数据库之外的数据库。 因为 Postgresql 要加载与数据库相关的系统目录(系统表),因此跨数据库的查询如何执行是不定的。
附加增值模块contrib/dblink允许采用函数调用实现跨库查询。当然用户也可以同时连接到不同的数据库执行查询然后在客户端合并结果。
21.如何让函数返回多行或多列?
在函数中返回数据记录集的功能是很容易使用的,详情参见: http://techdocs.postgresql.org/guides/SetReturningFunctions
22.为什么我在使用PL/Pgsql函数存取临时表时会收到错误信息“relation with OID ##### does not exist”?
PL/Pgsql会缓存函数的内容,由此带来的一个不好的副作用是若一个 PL/Pgsql 函数访问了一个临时表,然后该表被删除并重建了,则再次调用该函数将失败,因为缓存的函数内容仍然指向旧的临时表。解决的方法是在 PL/Pgsql 中用EXECUTE 对临时表进行访问。这样会保证查询在执行前总会被重新解析。