2010-02-03 Wed
鼓,国人最熟悉不过的一种打击乐器。古人打仗用鼓,祭祀用鼓,到衙门打官司也要敲一下鼓,办喜事则敲锣打鼓,连和尚庙都有晨钟暮鼓。发展至今,鼓已经成为民乐中最重要的乐器之一。但鼓,不仅仅中国有,也不一定就是中国人发明的,印度人,非洲人,西洋人都有属于他们本民族的鼓。各地的鼓,原理都差不多,但用的材料,制作的程序,敲打的工具、手法,对鼓乐的理解却不尽相同。即便在我国,也分有很多种鼓。
鼓在日本传统音乐中的地位也是非常高的,鼓乐甚至被认为是日本的国乐。虽然有人认为,日本的鼓是从中国传过去的,但并没有什么证据。昨天,在上海东方卫视的《全家都来赛》,一个来自台湾的家庭乐队“太鼓达人”演奏了一段鼓乐,无论是从乐队的名字,还是击鼓的手法,甚至连演出时的衣着,一看便知,他们表演的,不是中国鼓乐,而是日本的“太鼓”。(经常玩游戏应该知道“太鼓达人”。)
然而,这段鼓乐表演却因为现场嘉宾和主持人的爱国情绪再加上本来就有点无知而被误解了。在那个台湾家庭表演结束后,有成员介绍了自己当年去日本学鼓的经历,其中有一句说,最初学习的时候那些日本的同学都看不起我。按说他的介绍已经提示了在场的嘉宾和观众,他学的是日本鼓,可也许是那句话太刺激人了,嘉宾们便开始了少见的莫名其妙的点评。先是一位舞蹈家,说中国的历史有多长,鼓的历史有多长,你们演奏出了中国鼓文化的精髓,而后是一位好男,一脸正气地对表演者说道,我劝你还是回到中国好。当中,主持人还让表演者蒙住眼睛打了一会鼓,说,你打出了中国人的自信。最后,连表演者的母亲似乎也被感染了,热泪盈眶话语哽咽地说了一通,我们华人太鼓如何如何之类的话。全场掌声雷动,结果,那个代表香港的全家着戏装唱广东歌演神雕侠侣的家庭输了。
整个过程看得我目瞪口呆。很荒唐,很悲哀。

今天是美国画家诺曼•洛克威尔(Norman Rockwell,1894-1978)诞辰116周年纪念日。洛克威尔是美国20世界早期的重要画家,他的作品记录了20世纪美国的发展与变迁。点击了解更多有关诺曼•洛克威尔。
今天上午我一个同事误truncate了一个表uplbth,她问我是否可以恢复?
我们先去看一下这个表现在的状况:
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_name='UPLBTH';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
------------------------------ --------------- ---------- --------------
CAIPRA UPLBTH 52210 95137
从结果里我们可以看到,这个表的data object id已经比其object id大了太多,极有可能是曾经被多次truncate过。
后来我问了一下她是否多次truncate过这个表,她说是。然后我对她说,你等我信儿吧。
熊哥曾经在"使用ODU恢复Truncate表"这篇文章里提到了如何确定被多次truncate后的data object id,我这里用另外一种方式来精确定位我要恢复的data object id。
利用的原理就是:oracle里有system回滚段,而oracle对数据字典的操作基本上是DML,既然是DML,那就好办了,我们有很大的概率可以成功执行flashback query。
回到刚才的例子,我首先从dba_objects里知道了uplbth的last_ddl_time是2010-2-3 10:18:57;接着,我们直接执行flashback query来确定在执行truncate操作的那个时间点之前uplbth的data object id:
SQL> select owner,object_name,object_id,data_object_id from dba_objects as of timestamp to_timestamp('2010-02-03 10:18:00','YYYY-MM-DD HH24:MI:SS') where object_name='UPLBTH';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
------------------------------ --------------- ---------- --------------
CAIPRA UPLBTH 52210 77675
可以看到,当时的data object id是77675,精确的确定了data object id后,剩下的事情就都交给ODU好了:
ODU> unload table caipra.uplbth object 77675
Unloading table: UPLBTH,object ID: 52210
Unloading segment,storage(Obj#=52210 DataObj#=77675 TS#=16 File#=15 Block#=18828 Cluster=0)
1888 rows unloaded
可以看到,我们成功恢复出来了1880条数据。
注意,这里你用logmnr在缺省情况下是挖不出来data object id的,朋友们可以自己试一下。Author:NinGoo posted on NinGoo.net
PostgreSQL也支持逻辑备库和物理备份两种方式。物理备份可以和Oracle一样实现联机热备份,并且同样也需要将数据库设置为归档模式。
逻辑备份
PostgreSQL提供了pg_dump/pg_dumpall两个程序可以用来将数据dump成文本文件,实现数据的逻辑备份。使用不同的参数,可以将数据dump成PostgreSQL专用的数据格式(生成copy语句)或者标准SQL语句(生成insert语句)格式。恢复只需要简单的使用psql将文件执行一遍即可。另外也可以使用pg_restore工具来恢复数据。
利用pg_dump备份test数据库(只有一张test表),包括重建表的DDL语句,授权语句等所有信息,生成copy格式的文件:
$ ./pg_dump test
--
-- PostgreSQL database dump
--
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: test; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
CREATE TABLE test (
i integer
);
ALTER TABLE public.test OWNER TO postgres;
--
-- Data for Name: test; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY test (i) FROM stdin;
1
2
\.
--
-- Name: public; Type: ACL; Schema: -; Owner: postgres
--
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM postgres;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO PUBLIC;
--
-- PostgreSQL database dump complete
--
利用pg_dump备份test库,只保存数据,insert语句格式:
[postgres@dbconsole bin]$ ./pg_dump --inserts -a test -- -- PostgreSQL database dump -- SET statement_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = off; SET check_function_bodies = false; SET client_min_messages = warning; SET escape_string_warning = off; SET search_path = public, pg_catalog; -- -- Data for Name: test; Type: TABLE DATA; Schema: public; Owner: postgres -- INSERT INTO test VALUES (1); INSERT INTO test VALUES (2); -- -- PostgreSQL database dump complete --
物理备份
和Oracle一样,物理备份可以分为冷备份和热备份。冷备份就是将数据库实例关闭,然后直接复制data目录的所有文件,恢复时只需要将文件copy到data目录,无须利用日志(WAL–Write-Ahead Logging)进行恢复。而热备份,则需要利用日志将数据库恢复到一致状态,因此需要先将数据库置于归档模式。
PostgreSQL归档模式使用参数archive_mode控制,这是一个静态参数,修改postgresql.conf文件,加入如下参数,然后重启生效:
archive_mode = on archive_command = 'cp "%p" /u01/postgresql/arch/"%f"' archive_timeout = 600
postgres=# show archive_mode; archive_mode -------------- on (1 row)
由于postgresql没有归档进程,因此归档是通过外部命令(OS)完成的,archive_command用于指定该外部命令,具体格式请参考文档。如果是linux归档到本地,使用cp即可,如果是到远程,则可以使用scp或者rsync。archive_timeout强制N秒以后进行一次归档,这个和Oracle的archive_lag_target参数的作用一样。当然也可以手工进行日志切换:
postgres=# select pg_switch_xlog(); pg_switch_xlog ---------------- 0/7000000 (1 row)
热备份前,需要先将数据库置于备份状态,这一点和Oracle的手工也备份也是一样的。该命令会导致一次checkpoint,可能在业务高峰期会带来一些压力和风险,因此备份还是需要安排在业务低谷期间执行比较稳妥。
postgres=# select pg_start_backup('test_backup');
pg_start_backup
-----------------
0/8000020
(1 row)
然后在os层面将data目录进行复制备份。完成后,再取消备份状态,该命令同时会执行一次日志切换,并进行归档,以保证热备份期间的日志都已经归档,保证恢复数据库到一致状态的所有日志都能从归档中找到:
postgres=# select pg_stop_backup(); pg_stop_backup ---------------- 0/8000088 (1 row)
备份完成后,可以在归档目录找到一个记录了本次备份信息的文件:
$ more 000000010000000000000008.00000020.backup START WAL LOCATION: 0/8000020 (file 000000010000000000000008) STOP WAL LOCATION: 0/8000088 (file 000000010000000000000008) CHECKPOINT LOCATION: 0/8000020 START TIME: 2010-02-03 12:24:57 CST LABEL: test_backup STOP TIME: 2010-02-03 12:24:59 CST
PostgreSQL官方并没有提供和Oracle的rman一样的备份工具,不过因为PostgreSQL是开源的数据库,因此也有一个开源的工具pg_rman可以使用,从命令行来看功能已经非常强大,暂时还没有测试,有兴趣的可以研究一下。
pg_rman [ OPTIONS ] { init | backup | restore | show [ DATE | timeline ] |
validate [ DATE ] | delete DATE }
Related Articles
PermLink: http://www.ningoo.net/html/2010/postgresql_backup.html
Add Comments(0) | Follow NinGoo@Twitter | Google Reader












