之前读到手册以下这段话一直不太理解,如下:
手册内容的一段话
PostgreSQL’s MVCC transaction semantics depend on being able to compare transaction ID (XID) numbers: a row version with an insertion XID greater than the current transaction’s XID is “in the future” and should not be visible to the current transaction
备注:要理解这段话,首先得知道每行记录插入时 pg 会分配给每行 tuple 一个 xid, 这个 xid 为系统隐含字段 xmin,那么任何比 xmin 值要大的事务被认为是将来的,而且将来的事务在当前事务中不可见;这样翻译有点难懂。
后来通过实验,总算理解了。
实验一: 验证未来事务在当前事务不可见
1.1 创建测试表并插入三条记录
1 2 3 4 5 6 7 8
mydb=> create table test_29 (id integer,name varchar(32 )); CREATE TABLEmydb=> insert into test_29 values (1 ,'a' ); INSERT 0 1 mydb=> insert into test_29 values (2 ,'b' ); INSERT 0 1 mydb=> insert into test_29 values (3 ,'c' ); INSERT 0 1
1.2 查询记录的 xmin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3341 3339 | 2 | b | 3341 3340 | 3 | c | 3341 (3 rows) mydb=> select txid_current(); txid_current -------------- 3342 (1 row) mydb=> select txid_current(); txid_current -------------- 3343 (1 row)
1.3 再次插入三条记录,并查询记录 xmin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
mydb=> insert into test_29 values (4 ,'d'); INSERT 0 1 mydb=> insert into test_29 values (5 ,'e'); INSERT 0 1 mydb=> insert into test_29 values (6 ,'f'); INSERT 0 1 mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3347 3339 | 2 | b | 3347 3340 | 3 | c | 3347 3344 | 4 | d | 3347 3345 | 5 | e | 3347 3346 | 6 | f | 3347 (6 rows)
备注:注意记录的 xmin 值。
1.4 查看控制文件:pg_controldata 输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
[postgres@pgb ~]$ pg_controldata pg_control version number: 903 Catalog version number: 201105231 Database system identifier: 5652547536925883229 Database cluster state: in production pg_control last modified: Wed 02 May 2012 09:27:56 PM CST Latest checkpoint location: 1/BC000020 Prior checkpoint location: 1/B8015934 Latest checkpoint's REDO location: 1/BC000020 Latest checkpoint's TimeLineID: 5 Latest checkpoint's NextXID: 0/3336 Latest checkpoint's NextOID: 66605 Latest checkpoint's NextMultiXactId: 1 Latest checkpoint's NextMultiOffset: 0 Latest checkpoint's oldestXID: 1670 Latest checkpoint's oldestXID's DB: 16386 Latest checkpoint's oldestActiveXID: 0 Time of latest checkpoint: Wed 02 May 2012 09:26:34 PM CST Minimum recovery ending location: 0/0 Backup start location: 0/0 Current wal_level setting: hot_standby Current max_connections setting: 100 Current max_prepared_xacts setting: 0 Current max_locks_per_xact setting: 64 Maximum data alignment: 4 Database block size: 8192 Blocks per segment of large relation: 1048576 WAL block size: 65536 Bytes per WAL segment: 67108864 Maximum length of identifiers: 64 Maximum columns in an index: 32 Maximum size of a TOAST chunk: 2000 Date/time type storage: 64-bit integers Float4 argument passing: by value Float8 argument passing: by reference
备注:Latest checkpoint s NextXID:值为 3336
1.5 关闭 PostgreSQL
1 2 3
[postgres@pgb ~]$ pg_ctl stop -m fast -D $PGDATA waiting for server to shut down.. .. .. done server stopped
1.6 再次查看 pg_controldata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
pg_control version number: 903 Catalog version number: 201105231 Database system identifier: 5652547536925883229 Database cluster state: shut down pg_control last modified: Wed 02 May 2012 09:29:34 PM CST Latest checkpoint location: 1/C0000020 Prior checkpoint location: 1/BC000020 Latest checkpoint's REDO location: 1/C0000020 Latest checkpoint's TimeLineID: 5 Latest checkpoint's NextXID: 0/3348 Latest checkpoint's NextOID: 66608 Latest checkpoint's NextMultiXactId: 1 Latest checkpoint's NextMultiOffset: 0 Latest checkpoint's oldestXID: 1670 Latest checkpoint's oldestXID's DB: 16386 Latest checkpoint's oldestActiveXID: 0 Time of latest checkpoint: Wed 02 May 2012 09:29:32 PM CST Minimum recovery ending location: 0/0 Backup start location: 0/0 Current wal_level setting: hot_standby Current max_connections setting: 100 Current max_prepared_xacts setting: 0 Current max_locks_per_xact setting: 64 Maximum data alignment: 4 Database block size: 8192 Blocks per segment of large relation: 1048576 WAL block size: 65536 Bytes per WAL segment: 67108864 Maximum length of identifiers: 64 Maximum columns in an index: 32 Maximum size of a TOAST chunk: 2000 Date/time type storage: 64-bit integers Float4 argument passing: by value Float8 argument passing: by reference
备注: Latest checkpoint s NextXID: 值发生了变化,值为 3348,这是因为关闭数据库时触发了 checkpoint。
1.7 我们尝试把 NextXID 设置成 3341 ,看看会出现什么情况
1 2 3 4
[postgres@pgb ~]$ pg_resetxlog -x 3341 $PGDATA Transaction log reset [postgres@pgb ~]$ pg_ctl start -D $PGDATA server starting
1.8 再次查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
[postgres@pgb ~]$ psql -h 127.0 .0 .1 mydb mydb psql (9.1 .0 ) Type "help" for help.mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3341 3339 | 2 | b | 3341 3340 | 3 | c | 3341 (3 rows) mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3342 3339 | 2 | b | 3342 3340 | 3 | c | 3342 (3 rows) mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3343 3339 | 2 | b | 3343 3340 | 3 | c | 3343 (3 rows) mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3344 3339 | 2 | b | 3344 3340 | 3 | c | 3344 (3 rows)
备注:上面一直只能查看到 test_29 表的前三条记录,后三条记录消失,那是因为后三条记录的 xmin 大于 3344,而当前事务ID 小于或等于 3344,所以后三条记录对于当前事务来说是未来的,所以在当前事务中不可见,接着查询看会出现什么情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3345 3339 | 2 | b | 3345 3340 | 3 | c | 3345 3344 | 4 | d | 3345 (4 rows) mydb=> select xmin,*,txid_current() from test_29; xmin | id | name | txid_current ------+----+------+-------------- 3338 | 1 | a | 3347 3339 | 2 | b | 3347 3340 | 3 | c | 3347 3344 | 4 | d | 3347 3345 | 5 | e | 3347 3346 | 6 | f | 3347 (6 rows)
备注:随着当前事务号的增加,后面的三条记录居然出现了。
按照上面 PostgreSQL MVCC 原理,那么可以模拟下数据库因为 Transaction ID Wraparound 失败,而造成所有数据消失的情况。
实验二: 模拟事务 “Transaction ID Wraparound” 失败,所有数据消失
2.1 操作前数据库信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
[postgres@pgb ~]$ psql -h 127.0 .0 .1 mydb mydb psql (9.1 .0 ) Type "help" for help.mydb=> /dt List of relations Schema | Name | Type | Owner --------+----------------+-------+------- mydb | ad_position_ad | table | mydb mydb | array_test | table | mydb mydb | phone | table | mydb mydb | phone_201202 | table | mydb mydb | test | table | mydb mydb | test_10 | table | mydb mydb | test_11 | table | mydb mydb | test_12 | table | mydb mydb | test_13 | table | mydb mydb | test_14 | table | mydb mydb | test_15 | table | mydb mydb | test_16 | table | mydb mydb | test_17 | table | mydb mydb | test_18 | table | mydb mydb | test_19 | table | mydb mydb | test_2 | table | mydb mydb | test_20 | table | mydb mydb | test_21 | table | mydb mydb | test_23 | table | mydb mydb | test_24 | table | mydb mydb | test_25 | table | mydb mydb | test_26 | table | mydb mydb | test_27 | table | mydb mydb | test_28 | table | mydb mydb | test_29 | table | mydb mydb | test_3 | table | mydb mydb | test_4 | table | mydb mydb | test_5 | table | mydb mydb | test_6 | table | mydb mydb | test_7 | table | mydb mydb | test_8 | table | mydb mydb | test_9 | table | mydb mydb | test_array | table | mydb mydb | test_integer | table | mydb mydb | test_name | table | mydb mydb | test_standby | table | mydb mydb | test_unlogged | table | mydb mydb | test_user | table | mydb (38 rows)
2.2 pg_controldata 输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
[postgres@pgb ~]$ pg_controldata pg_control version number: 903 Catalog version number: 201105231 Database system identifier: 5652547536925883229 Database cluster state: in production pg_control last modified: Sat 05 May 2012 09:25:43 PM CST Latest checkpoint location: 1/C4000270 Prior checkpoint location: 1/C4000020 Latest checkpoint's REDO location: 1/C4000240 Latest checkpoint's TimeLineID: 5 Latest checkpoint's NextXID: 0/3348 Latest checkpoint's NextOID: 66608 Latest checkpoint's NextMultiXactId: 1 Latest checkpoint's NextMultiOffset: 0 Latest checkpoint's oldestXID: 1670 Latest checkpoint's oldestXID's DB: 16386 Latest checkpoint's oldestActiveXID: 3348 Time of latest checkpoint: Sat 05 May 2012 09:25:43 PM CST Minimum recovery ending location: 0/0 Backup start location: 0/0 Current wal_level setting: hot_standby Current max_connections setting: 100 Current max_prepared_xacts setting: 0 Current max_locks_per_xact setting: 64 Maximum data alignment: 4 Database block size: 8192 Blocks per segment of large relation: 1048576 WAL block size: 65536 Bytes per WAL segment: 67108864 Maximum length of identifiers: 64 Maximum columns in an index: 32 Maximum size of a TOAST chunk: 2000 Date/time type storage: 64-bit integers Float4 argument passing: by value Float8 argument passing: by reference
2.3 关闭数据库
1 2 3
[postgres@pgb ~]$ pg_ctl stop -m fast -D $PGDATA waiting for server to shut down.. .. .. done server stopped
2.4 重置 xid,设置较小的 xid
1 2 3
[postgres@pgb ~]$ pg_resetxlog -x 100 $PGDATA Transaction log reset 备注:这里将 xid 重置成 100 , 看下接下来会发生什么情况。
2.5 重启数据库并查看
1 2 3 4 5 6 7 8 9 10
[postgres@pgb ~]$ psql -h 127.0.0.1 mydb mydb psql (9.1.0) Type "help" for help. mydb => /dt No relations found.mydb => select txid_current(); txid_current -------------- 100 (1 row)
备注:所有表消失。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/237847.html