轻松解决PostgreSQL数据库的操作问题

轻松解决PostgreSQL数据库的操作问题

轻松解决PostgreSQL数据库的操作问题  

发布时间:2008.03.06 05:10     来源:赛迪网    作者:Alan

4.1.如何只选择一个查询结果的头几行?或是随机的一行?

如果你只是要提取几行数据,并且你在执行查询中知道确切的行数,你可以使用LIMIT功能。 如果有一个索引与 ORDER BY中的条件匹配,PostgreSQL 可能就只处理要求的头几条记录, (否则将对整个查询进行处理直到生成需要的行)。如果在执行查询功能时不知道确切的记录数, 可使用游标(cursor)和FETCH功能。


可使用以下方法提取一行随机记录的:


SELECT  cols
FROM tab
ORDER BY random()
LIMIT 1 ;

4.2.如何查看表、索引、数据库以及用户的定义?如何查看psql里用到的查询指令并显示它们?

在psql中使用 /dt 命令来显示数据表的定义,要了解psql中的完整命令列表可使用/? ,另外,你也可以阅读 psql 的源代码 文件pgsql/src/bin/psql/describe.c,它包括为生成psql反斜杠命令的输出的所有 SQL 命令。你还可以带 -E 选项启动 psql, 这样它将打印出你在psql中所给出的命令执行时的内部实际使用的SQL查询语句。PostgreSQL也提供了一个兼容SQL的INFORMATION SCHEMA接口, 你可以从这里获取关于数据库的信息。


在系统中也有一些以pg_ 打头的系统表也描述了表的定义。


使用 psql -l 指令可以列出所有的数据库。


也可以浏览一下 pgsql/src/tutorial/syscat.source文件,它列举了很多可从数据库系统表中获取信息的SELECT语法。


4.3.如何更改一个字段的数据类型?

在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 指令来使系统收回无效数据所占用的空间。


4.4.单条记录,单个表,单个数据库的最大限制是多少?

下面是一些限制:


单个数据库最大尺寸? 无限制(已存在有 32TB 的数据库)

单个表的最大尺寸? 32 TB

一行记录的最大尺寸? 1.6 TB

一个字段的最大尺寸? 1 GB

一个表里最大行数? 无限制

一个表里最大列数? 250-1600 (与列类型有关)

一个表里的最大索引数量? 无限制


当然,实际上没有真正的无限制,还是要受可用磁盘空间、可用内存/交换区的制约。 事实上,当上述这些数值变得异常地大时,系统性能也会受很大影响。


单表的最大大小 32 TB 不需要操作系统对单个文件也需这么大的支持。大表用多个 1 GB 的文件存储,因此文件系统大小的限制是不重要的。


如果缺省的块大小增长到 32K ,最大的单表大小和最大列数还可以增加到四倍。


有一个限制就是不能对大小多于2000字节的列创建索引。幸运地是这样的索引很少用到。通过对多字节列的内容进行MD5哈稀运算结果进行函数索引可对列的唯一性得到保证, 并且全文检索允许对列中的单词进行搜索。


4.5.存储一个典型的文本文件里的数据需要多少磁盘空间?

一个 Postgres 数据库(存储一个文本文件)所占用的空间最多可能需要相当于这个文本文件自身大小5倍的磁盘空间。


例如,假设有一个 100,000 行的文件,每行有一个整数和一个文本描述。 假设文本串的平均长度为20字节。文本文件占用 2.8 MB。存放这些数据的PostgreSQL数据库文件大约是 6.4 MB:


28 字节: 每行的头(大约值)
24 字节: 一个整数型字段和一个文本型字段
+  4 字节: 页面内指向元组的指针
----------------------------------------
56 字节每行

PostgreSQL 数据页的大小是 8192 字节 (8 KB),则:

8192 字节每页
-------------------   =  146 行/数据页(向下取整)
56 字节每行

100000 数据行
--------------------  =  685 数据页(向上取整)
146 行/数据页

685 数据页 * 8192 字节/页  = 5,611,520 字节(5.6 MB)



索引不需要这么多的额外消耗,但也确实包括被索引的数据,因此它们也可能很大。


空值NULL存放在位图中,因此占用很少的空间。


4.6.为什么我的查询很慢?为什么这些查询没有利用索引?

并非每个查询都会自动使用索引。只有在表的大小超过一个最小值,并且查询只会选中表中较小比例的记录时才会采用索引。 这是因为索引扫描引起的随即磁盘存取可能比直接地读取表(顺序扫描)更慢。


为了判断是否使用索引,PostgreSQL必须获得有关表的统计值。这些统计值可以使用 VACUUM ANALYZE,或 ANALYZE 获得。 使用统计值,优化器知道表中有多少行,就能够更好地判断是否利用索引。 统计值对确定优化的连接顺序和连接方法也很有用。在表的内容发生变化时,应定期进行统计值的更新收集。


索引通常不用于 ORDER BY 或执行连接。对一个大表的一次顺序扫描再做一次排序通常比索引扫描要快。然而,如果将 LIMIT 和 ORDER BY 结合在一起使用的话,通常将会使用索引,因为这时仅返回表中的一小部分记录。


如果你确信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和数值型的索引。


4.7.我如何才能看到查询优化器是怎样评估处理我的查询?

参考 EXPLAIN 手册页。


4.8.我怎样做正则表达式搜索和大小写无关的正则表达式查找?怎样利用索引进行大小写无关查找?

操作符 ~ 处理正则表达式匹配,而 ~* 处理大小写无关的正则表达式匹配。大小写无关的 LIKE 变种成为 ILIKE。


大小写无关的等式比较通常写做:


SELECT *
FROM tab
WHERE lower(col) = 'abc';

这样将不会使用标准的索引。但是可以创建一个在这种情况下使用的表达式索引:


CREATE INDEX tabindex ON tab (lower(col));

如果上述索引在创建时加入UNIQUE约束,虽然索引字段自身内容可以存储大小写不限的内容,但如果有UNIQUE约束后,这些内容不能仅仅是大小写不同(否则会造成冲突)。为了保证不发生这种情况,可以使用CHECK约束条件或是触发器在录入时进行限制。


4.9.在一个查询里,我怎样检测一个字段是否为 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)




4.10.各种字符类型之间有什么不同?

类型 内部名称 说明

VARCHAR(n) varchar 指定了最大长度,变长字符串,不足定义长度的部分不补齐

CHAR(n) bpchar 定长字符串,实际数据不足定义长度时,以空格补齐

TEXT text 没有特别的上限限制(仅受行的最大长度限制)

BYTEA bytea 变长字节序列(使用NULL字符也是允许的)

"char" char 单个字符


在系统表和在一些错误信息里你将看到内部名称。


上面所列的前四种类型是"varlena"(变长)类型(也就是说,开头的四个字节是长度,后面才是数据)。 于是实际占用的空间比声明的大小要多一些。 然而这些类型如定义很长时都可以被压缩存储,因此磁盘空间也可能比预想的要少。


VARCHAR(n) 在存储限制了最大长度的变长字符串是最好的。 TEXT 适用于存储最大可达 1G左右但未定义限制长度的字符串。


CHAR(n) 最适合于存储长度相同的字符串。 CHAR(n)会根据所给定的字段长度以空格补足(不足的字段内容), 而 VARCHAR(n) 只存储所给定的数据内容。 BYTEA 用于存储二进制数据,尤其是包含 NULL 字节的值。这些类型具有差不多的性能。


4.11.1.我怎样创建一个序列号或是自动递增的字段?

PostgreSQL 支持 SERIAL 数据类型。(字段定义为SERIAL后)将自动创建一个序列生成器,例如:


CREATE TABLE person (
      id   SERIAL,
      name TEXT
   );
会自动转换为以下SQL语句:

   CREATE SEQUENCE person_id_seq;
   CREATE TABLE person (
      id   INT4 NOT NULL DEFAULT nextval('person_id_seq'),
      name TEXT
   );


参考 create_sequence 手册页获取关于序列生成器的更多信息。


4.11.2) 我如何获得一个插入的序列号的值?

一种方法是在插入之前先用函数 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 对象的名称将会是 __seq, 这里 table 和 serialcolumn 分别是你的表的名称和你的 SERIAL 字段的名称。

类似的,在 SERIAL 对象缺省插入后你可以用函数 currval() 检索刚赋值的 SERIAL 值,例如:

execute("INSERT INTO person (name) VALUES ('Blaise Pascal')");
new_id = execute("SELECT currval('person_id_seq')");






4.11.3) 同时使用 currval() 会导致和其他用户的冲突情况吗?

不会。currval() 返回的是你本次会话进程所赋的值而不是所有用户的当前值。



4.11.4) 为什么不在事务异常中止后重用序列号呢?为什么在序列号字段的取值中存在间断呢?

为了提高并发性,序列号在需要的时候赋予正在运行的事务,并且在事务结束之前不进行锁定, 这就会导致异常中止的事务后,序列号会出现间隔。


4.12) 什么是 OID ?什么是 CTID ?

PostgreSQL 里创建的每一行记录都会获得一个唯一的OID,除非在创建表时使用WITHOUT OIDS选项。 OID创建时会自动生成一个4字节的整数,所有 OID 在相应PostgreSQL服务器中均是唯一的。 然而,它在超过40亿时将溢出, OID此后会出现重复。PostgreSQL 在它的内部系统表里使用 OID 在表之间建立联系。


在用户的数据表中,最好是使用SERIAl来代替OID 因为SERIAL只要保证在单个表中的数值是唯一的就可以了,这样它溢出的可能性就非常小了, SERIAL8可用来保存8字节的序列数值。


CTID 用于标识带着数据块(地址)和(块内)偏移的特定的物理行。 CTID 在记录被更改或重载后发生改变。索引数据使用它们指向物理行。


4.13.为什么我收到错误信息“ERROR: Memory exhausted in AllocSetAlloc()”?

这很可能是系统的虚拟内存用光了,或者内核对某些资源有较低的限制值。在启动 postmaster 之前试试下面的命令:


ulimit -d 262144
limit datasize 256m




取决于你用的 shell,上面命令只有一条能成功,但是它将把你的进程数据段限制设得比较高, 因而也许能让查询完成。这条命令应用于当前进程,以及所有在这条命令运行后创建的子进程。 如果你是在运行SQL客户端时因为后台返回了太多的数据而出现问题,请在运行客户端之前执行上述命令。


4.14.我如何才能知道所运行的PostgreSQL的版本?

从 psql 里,输入 SELECT version();指令。


4.15.我如何创建一个缺省值是当前时间的字段?

使用 CURRENT_TIMESTAMP:


CREATE TABLE test (x int, modtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

4.16.我怎样进行 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)。


4.17.如何使用涉及多个数据库的查询?

没有办法查询当前数据库之外的数据库。 因为PostgreSQL要加载与数据库相关的系统目录(系统表),因此跨数据库的查询如何执行是不定的。


附加增值模块contrib/dblink允许采用函数调用实现跨库查询。当然用户也可以同时连接到不同的数据库执行查询然后在客户端合并结果。


4.18.如何让函数返回多行或多列数据?

在函数中返回数据记录集的功能是很容易使用的,详情参见: http://techdocs.postgresql.org/guides/SetReturningFunctions


4.19.为什么我在使用PL/PgSQL函数存取临时表时会收到错误信息“relation with OID ##### does not exist”?

PL/PgSQL会缓存函数的脚本内容,由此带来的一个不好的副作用是若一个 PL/PgSQL 函数访问了一个临时表,然后该表被删除并重建了,则再次调用该函数将失败, 因为缓存的函数内容仍然指向旧的临时表。解决的方法是在 PL/PgSQL 中用EXECUTE 对临时表进行访问。这样会保证查询在执行前总会被重新解析。


4.20.目前有哪些数据复制方案可用?

“复制”只是一个术语,有好几种复制技术可用,每种都有优点和缺点:


主/从复制方式是允许一个主服务器接受读/写的申请,而多个从服务器只能接受读/SELECT查询的申请, 目前最流行且免费的主/从PostgreSQL复制方案是 Slony-I 。


多个主服务器的复制方式允许将读/写的申请发送给多台的计算机,这种方式由于需要在多台服务器之间同步数据变动 可能会带来较严重的性能损失,Pgcluster是目前这种方案 中最好的,而且还可以免费下载。


也有一些商业需付费和基于硬件的数据复制方案,支持上述各种复制模型。


4.21.为何查询结果显示的表名或列名与我的查询语句中的不同?为何大写状态不能保留?

最常见的原因是在创建表时对表名或是列名使用了双引号“”,当使用了双引号后,表名或列名(称为标识符)存储时是区分 大小写的, 这意谓着你在查询时表名或列名也应使用双引号,一些工具软件,像pgAdmin会在发出创建表的指令时自动地在每个标识符上加双引号。 因此,为了标识符的统一,你应该:


在创建表时避免将标识符使用双引号引起来。

在标识符中只使用小写字母。

(为了与已存在的标识符相同)在查询中使用双引号将标识符引起来。

(责任编辑:卢兆林)
昵称: 〇〇  时间: 2009-03-06 08:58:00
如何将Oracle的功能在PostgreSQL中使用  

发布时间:2008.03.06 16:21     来源:赛迪网    作者:水晶

问题:如何将Oracle中的功能在PostgreSQL中使用?

解答:本人使用Oracle和PostgreSQL数年,一直试图将Oracle中许多先进的功能在PostgreSQL中使用,所以也在这方面一直比较注意,下面先整理出3点,希望对你有所帮助。


(1)和Oracle类似的dblink功能


使用过oracle的人都知道,oracle有个很先进的功能叫:dblink,能够在一个数据库中操作另外一个远程的数据库,比如:一个数据库在中国北 京,另外一台数据库在中国上海,我可以在北京这台数据库上面建立一个到上海数据库的dblink,然后可以在北京这台数据库上面对上海的数据库进行 query或者update或者delete。这个先进的功能在PostgreSQL的原代码的:contrib/dblink中已经有了,大家可以像这 样将他编译并安装到我们的数据库中。


#cd contrib/dblink
#make
#make install




假设我们的postgresql安装在:/home/pgsql中。


make install后,在/home/pgsql/lib/中会有一个:dblink.so文件。这就是使用dblink必须的函数文件。另外,在/home /pgsql/share/contrib中会有一个dblink.sql文件,这就是安装dblink.so的函数所需要的sql语句。


可以像这样安装dblink的所有函数:


#cat dblink.sql|psql
[pgsql@webtrends contrib]$ cat dblink.sql |psql
CREATE FUNCTION
[pgsql@webtrends contrib]$




说明我们的函数安装成功。


下面可以使用dblink的所有先进功能了。


你可以先看看dblink.sql中的一些函数申明,让我们更了解他的作用。


下面进入psql:


pgsql=# select dblink_connect('host=localhost user=pgsql password=');
dblink_connect
----------------
OK
(1 row)

这个函数用来建立到远程数据库的连接。

你可以像这样想远程的数据库中insert一条记录:

pgsql=# select dblink_exec('insert into student values(/'linux_prog/',/'12345/')');
dblink_exec
-------------------
INSERT 22516276 1
(1 row)




现在我们检索我们刚才insert的记录:怎么样?刚才insert的记录已经在里面了。


dblink的功能非常强大,我上面列举的只是他的最简单的应用。大家可以参考PostgreSQL的source code下面:


contrib/dblink/sql/dblink.sql仔细看一下。


(2)找出系统中性能很差的SQL,并加以优化


我们在做Oracle系统管理的时候,经常做的事情是:


首先看看系统中哪几条SQL的性能最差,通过linux命令:top -c找出该最前面的几个oracle进程的PID,然后在oracle的相关view中将这些SQL找出来,然后去看看这些SQL的execute plan,然后进行相关的优化。


PostgreSQL也提供了这样先进的功能。


首先,在postgresql.conf中把stats_command_string = true打开,使PostgreSQL的stats collector process监控每个session的sql语句。


编写相关的脚本:


viewsql.sh:
#!/bin/sh
######################################################
# viewsql.sh #
# Author:linux_prog #
# use to show all active session's sql in PostgreSQL.#

######################################################
if test -z $1 ;then
echo "Usage:$0 pid"
exit 10
fi
echo "select * from (SELECT pg_stat_get_backend_pid(s.backendid) AS
procpid, pg_stat_get_backend_activity(s.backendid) AS current_query FROM
(SELECT pg_stat_get_backend_idset() AS backendid) AS s) as querystring
where procpid=$1;" | psql




这个脚本是显示指定的pid的session目前正在执行的sql语句。


比如:


我用top -c,结果是:


3665 pgsql 15 0 124M 124M 122M R 30.0 2.1 0:04 postgres: pgsql pgsql [local] INSERT


可以看到:3665这个pid显示在第一条,说明它的sql可能效率比较低。


[pgsql@webtrends bin]$ ./viewsql.sh 3665
procpid | current_query
---------+---------------------------------------------------
3665 | insert into access_log select * from access_log ;
(1 row)


我们可以看到他正在进行的SQL语句,然后我们就可以对这些SQL进行性能的优化。

如果,如果是一条select语句,执行速度狂慢的话,我们可以用explain来看看他的execute plan,看是否有合适的index或者是否是某个table很久没有analyze过了,等等。


另外,可以提供一个KILL一个session的脚本,比如:有个session占用的资源太多,如果不kill掉他的话,可能会导致系统DOWN机。


killsession.sh:
#!/bin/sh
################################################
# Author:linux_prog #
# use to kill one session. #
################################################
if test -z $1; then
echo "Usage:$0 pid"
exit 10
fi
SID=$1
echo "select pg_cancel_backend($SID);"|psql
比如:我执行:
[pgsql@webtrends bin]$ ./killsession.sh 3665
pg_cancel_backend
-------------------
1
(1 row)

刚才那个很占资源的session的目前的SQL操作就被cancel掉了。

在3665的psql中会显示:

pgsql=# insert into access_log select * from access_log ;

ERROR: canceling query due to user request



(3)清楚的知道每个table或者index的大小


每一个DBA都应该知道,IO的瓶颈是所有数据库性能的瓶颈。所以我们在设计表结构的时候,一定要尽量的减少每个字段的大小,只有这样,table的size才会尽量的小。


还有,我们在进行SQL调整的时候,首先做的,肯定是对大的TABLE的performance turnning。


因此,我们很清楚的知道每个table或者index所占用的磁盘大小是很有必要的,在oracle中可以直接访问dba_segments这个view来知道每个TABLE或者INDEX的大小。


PostgreSQL的contrib/dbsize中也有这样的一个模块。


大家可以像上面安装dblink那样安装dbsize.so。


像这样查看table:access_log的大小:


pgsql=# select relation_size('access_log')/1024/1024 ||'M' as dbsize;

dbsize

--------

332M

(1 row)

像这样查看index:test_idx的大小:


pgsql=# select relation_size('test_idx')/1024/1024 ||'M' as dbsize;

dbsize

--------

0M

(1 row)

我们先可以写个脚本来进行这样的操作(需要大家自己完成)。

以上的内容都很实用,如果你能够深刻理解的话,一定能够在日常的数据库管理中发挥不可小看的工作。(责任编辑:卢兆林)
昵称: 〇〇  时间: 2009-03-06 09:01:00
PostgreSQL数据库随程序打包的相关问题  

发布时间:2008.03.06 16:35     来源:赛迪网    作者:廉子桥

Windows版本的PostgresQL安装过程较为复杂(本文特指8.0.3以下版本),官方使用了pginstaller将PostgresQL打为一个msi包,单独安装问题不大,但是有以下几个问题:  

1、远程桌面安装兼容性差(目前官方的说法是除了win2003都有问题)

2、无法随程序打包

3、安装后的建库工作会受到分区格式的影响

针对以上问题,现给出如下解决方案:

◆A、在随便一台机器上装好pgsql,并且建好库、导好数据

◆B、将整个pgsql的安装好的目录复制到一个临时文件夹(例如d:/temp),应该包括:

bin、data、include、lib、share等,视情况可以考虑加入pgadminIII

◆C、在临时文件夹中建立dll目录,包括以下5个文件:

libeay32.dll/libiconv-2.dll/libintl-2.dll/libpq.dll/ssleay32.dll

(都可以在安装好的机器中找到)

◆D、网上去找个ntright.exe文件,放在bin目录里(随便放哪,但是后面安装完成最好删掉)

——修正:网上再去找个netuser.exe,放在bin目录里

——感谢canders兄的提醒,之前没考虑到用户帐号过期问题  

◆E、在临时文件夹中建立setup.bat文件,内容如下:

REM 创建postgres用户,用来管理服务

net user postgres [passwd] /add /PASSWORDCHG:NO

REM 让postgres用户不属于users组,官方说不安全

net localgroup users postgres /delete

REM 设置postgres用户密码永不过期,技巧!!

./bin/netuser postgres /pwnexp:y

REM 拷贝文件,力气活

copy ./dll/*.* %windir%/system32 /Y

REM 赋予postgres用户logon as service权限,技巧!!

REM 插一句废话,ntrights.exe的参数列表里没有我用的这个

./bin/ntrights.exe -u postgres +r SeServiceLogonRight

REM 以下摘自pginstaller源文件,照做,主要是postgres用户的文件权限

REM 其实是给ntfs用的,xp在fat32格式时会报错,无视!

cacls . /E /T /D postgres

cacls . /E /T /G postgres:R

cacls ./data /E /T /P postgres:C

REM 建立PostgresQL服务,不要加入-L,注意%CD%的用法

REM 否则事件查看器将变成windows写情书给你的地方

./bin/pg_ctl register -N PgSQL -U postgres -P [passwd] -D "%CD%/data"

REM 启动刚才建好的服务

net start PgSQL

◆F、把整个临时目录打包分发,解压后只要运行setup.bat就完事大吉。

◆G、有经验的朋友可以在bat中加入条件判断或者其他标志,我就偷懒了。

注:在win2000、winxp、win2003 (ntfs、fat32、远程桌面、中文父文件夹)下通过测试。

(责任编辑:卢兆林)
昵称: 〇〇  时间: 2009-03-06 09:05:00

21.2. 字符集支持PostgreSQL 里面的字符集支持你能够以各种字符集存储文本, 包括单字节的字符集,比如 ISO 8859 系列和 EUC (扩展 Unix 编码 Extended Unix Code),UTF-8 和 Mule 国际编码。所有字符集都可以在服务器上透明地使用。 (如果你使用了来自其它数据源地扩展函数,那么它取决于他们是否正确地书写了代码。) 缺省的字符集是在使用 initdb 初始化你的 PostgreSQL 数据库集群的时候选择的。 在你的使用 createdb 或者 SQL 命令 CREATE DATABASE 的时候是可以覆盖这个缺省的。因此,你可以有多个数据库,每个都有不同的字符集。
21.2.1. 支持字符集编码Table 21-1 显示了可以用在服务器的字符集。
Table 21-1. 服务器字符集
[tr]名字描述语言字节/字符别名[/tr]

BIG5 大五 繁体中文 1-2 WIN950 , Windows950
EUC_CN 扩展的 UNIX 代码-CN 简体中文 1-3
EUC_JP 扩展的 UNIX 代码-JP 日文 1-3
EUC_KR 扩展的 UNIX 代码-KR 韩文 1-3
EUC_TW 扩展的 UNIX 代码-TW 繁体中文,中国台湾省 1-3
GB18030 国家标准 中文 1-2
GBK 扩展的国家标准 简体中文 1-2 WIN936 , Windows936
ISO_8859_5 ISO 8859-5, ECMA 113 拉丁/西里尔语 1
ISO_8859_6 ISO 8859-6, ECMA 114 拉丁/阿拉伯语 1
ISO_8859_7 ISO 8859-7, ECMA 118 拉丁/希腊语 1
ISO_8859_8 ISO 8859-8, ECMA 121 拉丁/希伯莱语 1
JOHAB JOHAB 韩语(Hangul) 1-3
KOI8 KOI8-R(U) 西里尔语 1 KOI8R
LATIN1 ISO 8859-1, ECMA 94 西欧语 1 ISO88591
LATIN2 ISO 8859-2, ECMA 94 中欧语 1 ISO88592
LATIN3 ISO 8859-3, ECMA 94 南欧语 1 ISO88593
LATIN4 ISO 8859-4, ECMA 94 北欧语 1 ISO88594
LATIN5 ISO 8859-9, ECMA 128 土耳其语 1 ISO88599
LATIN6 ISO 8859-10, ECMA 144 北欧,日耳曼语(Nordic) 1 ISO885910
LATIN7 ISO 8859-13 波罗的海语(Baltic) 1 ISO885913
LATIN8 ISO 8859-14 凯尔特语(Celtic) 1 ISO885914
LATIN9 ISO 8859-15 带有欧洲语系和语调的 LATIN1 1 ISO885915
LATIN10 ISO 8859-16, ASRO SR 14111 罗马尼亚语(Romanian) 1 ISO885916
MULE_INTERNAL Mule 国际编码 多语种 Emacs 1-4
SJIS Shift JIS 日语 1-2 Mskanji , ShiftJIS , WIN932 , Windows932
SQL_ASCII 未声明(见文本) 任意 1
UHC 统一韩语(Hangul)编码 韩语 1-2 WIN949 , Windows949
UTF8 Unicode, 8-bit 全部 1-4 Unicode
WIN866 Windows CP866 西里尔语 1 ALT
WIN874 Windows CP874 泰国语 1
WIN1250 Windows CP1250 中欧语 1
WIN1251 Windows CP1251 西里尔语 1 WIN
WIN1252 Windows CP1252 西欧语 1
WIN1256 Windows CP1256 阿拉伯语 1
WIN1258 Windows CP1258 越南语 1 ABC , TCVN , TCVN5712 , VSCII


并非所有API支持上面列出的编码。比如, PostgreSQL JDBC 驱动就不支持MULE_INTERNALLATIN6LATIN8LATIN10
SQL_ASCII 设置与其它设置表现得相当不同。如果服务器字符集是 SQL_ASCII , 服务器把字节值 0-127 的数值根据 ASCII 标准解析,而字节值未 128-255 的则当作未解析的字符。 如果设置为 SQL_ASCII ,就不会有编码转换。因此,这个设置基本不是用来声明所使用的编码的, 因为这个声明会忽略编码。在大多数情况下,如果你使用了任何非 ASCII 数据,那么使用 SQL_ASCII 设置都是不明智的,因为 PostgreSQL 会无法帮助你转换或者校验非 ASCII 字符。

21.2.2. 设置字符集initdb 为一个 PostgreSQL 集群定义缺省的字符集,比如:
initdb -E EUC_JP把缺省字符集设置为 EUC_JP (用于日文的扩展的 Unix 编码)。 如果你喜欢用长选项声明的话,你可以用 --encoding 代替 -E 。 如果没有给出-E 或者--encoding 选项, initdb 将基于制定的区域或者缺省区域试图判断合适的编码。
你可以创建一个有着不同编码的数据库:
createdb -E EUC_KR korean将创建一个使用EUC_KR 字符集的名字叫 korean 的数据库。 另外一种实现方法是使用 SQL 命令:
CREATE DATABASE korean WITH ENCODING 'EUC_KR';数据库的编码是用系统表 pg_database 里的一个 编码字段 代表的。 你可以用psql-l 选项或 /l 命令列出这些编码。
$ psql -l            List of databases   Database    |  Owner  |   Encoding---------------+---------+--------------- euc_cn        | t-ishii | EUC_CN euc_jp        | t-ishii | EUC_JP euc_kr        | t-ishii | EUC_KR euc_tw        | t-ishii | EUC_TW mule_internal | t-ishii | MULE_INTERNAL postgres      | t-ishii | EUC_JP regression    | t-ishii | SQL_ASCII template1     | t-ishii | EUC_JP test          | t-ishii | EUC_JP utf8          | t-ishii | UTF8(9 rows)

Important: 虽然你可以给一个数据库声明你需要的任何编码,但选择一个与你选择的区域不一致的编码还是不妥的做法。 LC_COLLATELC_CTYPE 设置暗示一个特定的编码, 与区域相关的操作(比如排序)在不兼容的编码里很有可能产生错误的解析。
因为这些区域设置都是由 initdb 冻结的, 所以在不同的数据库里使用不同的编码更多是理论而不是现实。 这些机制很有可能在将来版本的 PostgreSQL 得到改进。
一个安全使用多种编码的方法是在 initdb 的时候把区域设置为 C 或者 POSIX ,这样旧关闭了任何实际的区域敏感性。



21.2.3. 服务器和客户端之间的自动字符集转换PostgreSQL 支持一些编码在服务器和前端之间的自动编码转换。 转换信息在系统表 pg_conversion 中存储。 你可以使用 SQL 命令 CREATE CONVERSION 创建一个新的转换。 PostgreSQL带着一些预定义的转换。它们在 Table 21-2 中列出。
Table 21-2. 客户/服务器字符集转换
[tr]服务器字符集可用客户端字符集[/tr]

BIG5 不支持做服务器端编码
EUC_CN EUC_CN , MULE_INTERNAL , UTF8
EUC_JP EUC_JP , MULE_INTERNAL , SJIS , UTF8
EUC_KR EUC_KR , MULE_INTERNAL , UTF8
EUC_TW EUC_TW , BIG5 , MULE_INTERNAL , UTF8
GB18030 不支持做服务器端编码
GBK 不支持做服务器端编码
ISO_8859_5 ISO_8859_5 , KOI8 , MULE_INTERNAL , UTF8 , WIN866 , WIN1251
ISO_8859_6 ISO_8859_6 , UTF8
ISO_8859_7 ISO_8859_7 , UTF8
ISO_8859_8 ISO_8859_8 , UTF8
JOHAB JOHAB , UTF8
KOI8 KOI8 , ISO_8859_5 , MULE_INTERNAL , UTF8 , WIN866 , WIN1251
LATIN1 LATIN1 , MULE_INTERNAL , UTF8
LATIN2 LATIN2 , MULE_INTERNAL , UTF8 , WIN1250
LATIN3 LATIN3 , MULE_INTERNAL , UTF8
LATIN4 LATIN4 , MULE_INTERNAL , UTF8
LATIN5 LATIN5 , UTF8
LATIN6 LATIN6 , UTF8
LATIN7 LATIN7 , UTF8
LATIN8 LATIN8 , UTF8
LATIN9 LATIN9 , UTF8
LATIN10 LATIN10 , UTF8
MULE_INTERNAL MULE_INTERNAL , BIG5 , EUC_CN , EUC_JP , EUC_KR , EUC_TW , ISO_8859_5 , KOI8 , LATIN1 to LATIN4 , SJIS , WIN866 , WIN1250 , WIN1251
SJIS 不支持做服务器端编码
SQL_ASCII 任意(不会发生编码转换)
UHC 不支持做服务器端编码
UTF8 所有支持的编码
WIN866 WIN866 , ISO_8859_5 , KOI8 , MULE_INTERNAL , UTF8 , WIN1251
WIN874 WIN874 , UTF8
WIN1250 WIN1250 , LATIN2 , MULE_INTERNAL , UTF8
WIN1251 WIN1251 , ISO_8859_5 , KOI8 , MULE_INTERNAL , UTF8 , WIN866
WIN1252 WIN1252 , UTF8
WIN1256 WIN1256 , UTF8
WIN1258 WIN1258 , UTF8


要想打开自动字符集转换功能,你必须告诉 PostgreSQL 你想在客户端使用的字符集(编码)。你可以用好几种方法实现这个目的。

  • 用 psql 里的 /encoding 命令。 /encoding 允许你动态修改客户端编码。 比如,把编码改变为 SJIS ,键入:
    /encoding SJIS
  • 使用 libpq 函数。 /encoding 在做此用途的时候实际上是调用 PQsetClientEncoding()
    int PQsetClientEncoding(PGconn *conn , const char *encoding );这里 conn 与后端的联接,而 encoding 是你想用的编码。如果编码设置成功它返回 0,否则返回 -1。本次联接的当前编码可以用下面函数显示:
    int PQclientEncoding(const PGconn *conn );请注意它只返回编码 ID,而不是象 EUC_JP 这样的编码符号字串。 要把编码 ID 转换为编码符号,你可以用:
    char *pg_encoding_to_char(int encoding_id );
  • 使用 SET client_encoding TO 。 可以用 SQL 命令设置客户端编码:
    SET CLIENT_ENCODING TO 'value ';你还可以把 SQL 语法里的 SET NAMES 用于这个目的:
    SET NAMES 'value ';查询当前客户端编码:
    SHOW client_encoding;返回缺省编码:
    RESET client_encoding;
  • 使用 PGCLIENTENCODING 。 如果在客户端的环境里定义了 PGCLIENTENCODING 环境变量, 那么在与服务器进行联接时将自动选择客户端编码。 (这个编码随后可以用上面谈到的任何其它方法覆盖。)
  • 使用client_encoding 配置变量。 如果在 postgresql.conf 里设置了 client_encoding 变量, 那么在与服务器建立了联接之后,这个客户端编码将自动选定。(这个设置随后可以被上面提到 的其他方法覆盖。)


假如无法进行特定的字符转换 — 比如, 你选的服务器编码是EUC_JP , 客户端是LATIN1 ,那么有些日文字符不能转换成LATIN1 。这时, 不能用LATIN1 字符集表示的字母将被转换成圆括弧包围的十六进制,像,(826C) 这样。
如果客户端字符集定义成了 SQL_ASCII ,那么编码转换会被关闭, 不管服务器的字符集是什么都一样。和服务器一样,除非你的工作环境全部是 ASCII 数据, 否则使用 SQL_ASCII 是不明智的。

21.2.4. 进一步阅读下面是学习各种类型的编码系统的好地方。

http://www.i18ngurus.com/docs/984813247.html 一整套有关字符集,编码以及代码页的文档。
ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/cjk.inf 详细地解释了第3.2节出现的EUC_JPEUC_CNEUC_KREUC_TW
http://www.unicode.org/ Unicode 的家目录。
RFC 2044 定义了UTF-8。

你可能感兴趣的:(轻松解决PostgreSQL数据库的操作问题)