对PostgreSQL cmin和cmax的理解

看例子:

开两个终端来对比:

在终端A:

[pgsql@localhost bin]$ ./psql

psql (9.1.2)

Type "help" for help.



pgsql=# begin;

BEGIN

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

(2 rows)



pgsql=# insert into tab01 values(3,'3');

INSERT 0 1

pgsql=# insert into tab01 values(4,'4');

INSERT 0 1

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

 1885 |    0 |    0 |    0 |         3 | 3

 1885 |    0 |    1 |    1 |         4 | 4

(4 rows)



pgsql=# 

此时的终端B:

[pgsql@localhost bin]$ ./psql

psql (9.1.2)

Type "help" for help.



pgsql=# select xmin,xmax,cmin,cmax, * from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

(2 rows)



pgsql=# 

然后再在终端A进行提交:

pgsql=# commit;

COMMIT

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

 1885 |    0 |    0 |    0 |         3 | 3

 1885 |    0 |    1 |    1 |         4 | 4

(4 rows)



pgsql=# 

此时,再在终端B进行观察:

pgsql=# select xmin,xmax,cmin,cmax, * from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

 1885 |    0 |    0 |    0 |         3 | 3

 1885 |    0 |    1 |    1 |         4 | 4

(4 rows)



pgsql=# 

 继续研究cmin是咋回事:

pgsql=# begin;

BEGIN

pgsql=# insert into tab01(id,cd) values(generate_series(5,6),'xx');

INSERT 0 2

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax |    id     | cd 

------+------+------+------+-----------+----

 1878 |    0 |    0 |    0 |         1 | 1

 1884 |    0 |    0 |    0 | 999888777 | 2

 1885 |    0 |    0 |    0 |         3 | 3

 1885 |    0 |    1 |    1 |         4 | 4

 1886 |    0 |    0 |    0 |         5 | xx

 1886 |    0 |    0 |    0 |         6 | xx

(6 rows)



pgsql=# 

可以说cmin可理解为一个事务里,执行了几次sql命令的顺序。

那么cmax呢?在前面的基础上继续执行,居然没有看到区别:

pgsql=# update tab01 set id=2 where cd = '2';

UPDATE 1

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax | id | cd 

------+------+------+------+----+----

 1878 |    0 |    0 |    0 |  1 | 1

 1885 |    0 |    0 |    0 |  3 | 3

 1885 |    0 |    1 |    1 |  4 | 4

 1886 |    0 |    0 |    0 |  5 | xx

 1886 |    0 |    0 |    0 |  6 | xx

 1886 |    0 |    1 |    1 |  2 | 2

(6 rows)



pgsql=# commit;

COMMIT

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;

 xmin | xmax | cmin | cmax | id | cd 

------+------+------+------+----+----

 1878 |    0 |    0 |    0 |  1 | 1

 1885 |    0 |    0 |    0 |  3 | 3

 1885 |    0 |    1 |    1 |  4 | 4

 1886 |    0 |    0 |    0 |  5 | xx

 1886 |    0 |    0 |    0 |  6 | xx

 1886 |    0 |    1 |    1 |  2 | 2

(6 rows)



pgsql=# 

 经过反复折腾,终于发现,其实 cmin和 cmax就是一个东西:

看源代码:

/* ----------------

 *        heap_getsysattr

 *

 *        Fetch the value of a system attribute for a tuple.

 *

 * This is a support routine for the heap_getattr macro.  The macro

 * has already determined that the attnum refers to a system attribute.

 * ----------------

 */

Datum

heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)

{

    Datum        result;



    Assert(tup);



    /* Currently, no sys attribute ever reads as NULL. */

    *isnull = false;



    switch (attnum)

    {

        case SelfItemPointerAttributeNumber:

            /* pass-by-reference datatype */

            result = PointerGetDatum(&(tup->t_self));

            break;

        case ObjectIdAttributeNumber:

            result = ObjectIdGetDatum(HeapTupleGetOid(tup));

            break;

        case MinTransactionIdAttributeNumber:

            result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));

            break;

        case MaxTransactionIdAttributeNumber:

            result = TransactionIdGetDatum(HeapTupleHeaderGetXmax(tup->t_data));

            break;

        case MinCommandIdAttributeNumber:

        case MaxCommandIdAttributeNumber:



            /* * cmin and cmax are now both aliases for the same field, which * can in fact also be a combo command id. XXX perhaps we should * return the "real" cmin or cmax if possible, that is if we are * inside the originating transaction? */

            result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));

            break;

        case TableOidAttributeNumber:

            result = ObjectIdGetDatum(tup->t_tableOid);

            break;

        default:

            elog(ERROR, "invalid attnum: %d", attnum);

            result = 0;            /* keep compiler quiet */

            break;

    }

    return result;

}

 

你可能感兴趣的:(PostgreSQL)