PostgreSQL LOGGED和UNLOGGED表性能与LOCK TABLE的使用比较

时间:2018-05-18 14:30:05

标签: postgresql locking logged

我正在尝试在PostgreSQL(10.3)中的UPDATELOGGED表上测量UNLOGGED速度。我想使用LOCK TABLE来防止其他应用程序相互干扰。

如果在不使用UPDATE的情况下执行LOCK TABLE,则LOGGED表获得~1K,UNLOGGED表获得~4K。

如果使用UPDATE执行LOCK TABLE,则两种表类型的结果都相同。

为什么LOCK TABLE在两种表类型中都返回相同的结果?

我的PL / pgSQL功能:

CREATE OR REPLACE FUNCTION public.myfunction(user_id integer, unitprice numeric(10,6), 
            islock boolean, useunlogged boolean) RETURNS integer AS
$BODY$
declare howMuch integer;
begin       
    if islock then
        if useunlogged then 
            LOCK TABLE credittable_unlogged IN ACCESS EXCLUSIVE MODE;
        else
            LOCK TABLE credittable IN ACCESS EXCLUSIVE MODE;
        end if;
    end if;
    if useunlogged then     
        select (credit_amount/unitprice)::integer into howMuch from credittable where userid=user_id and credit_amount>=unitprice;
        if howMuch is null then 
            select 0 into howMuch;
        else
            update credittable set credit_amount=credit_amount-unitprice where userid=user_id;
        end if;    
    else 
        select (credit_amount/unitprice)::integer into howMuch from credittable_unlogged where userid=user_id and credit_amount>=unitprice;
        if howMuch is null then 
           select 0 into howMuch;
        else
            update credittable_unlogged set credit_amount=credit_amount-unitprice where userid=user_id;
        end if;  
    end if;
    RETURN howMuch;
 end;
 $BODY$
   LANGUAGE plpgsql VOLATILE
    COST 100;
 ALTER FUNCTION public.myfunction(integer, numeric, boolean, boolean)
    OWNER TO postgres;

我的Java代码:

for(int i=1;i<=4;i++){
    long startTime = System.nanoTime();
    int counter = 0;        
    while ((System.nanoTime() - startTime) < 1000000000L) {
        CallableStatement callst = null;
        try {
            String sql = "{? = call public.myfunction(?,?,?,?) }";
            callst = con.prepareCall(sql);
            callst.registerOutParameter(1, Types.INTEGER);
            callst.setInt(2, 123456);
            callst.setBoolean(3, (i > 2));
            callst.setBoolean(4, (i%2 != 0));
            callst.setBigDecimal(3, BigDecimal.valueOf(0.001));
            callst.execute();
            int howMuch = callst.getInt(1);                
            counter++;                
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (callst != null) {
                callst.close();
            }
        }
    }
    System.out.println("Counter :"+counter);
}   

1 个答案:

答案 0 :(得分:3)

您在此测量的很多内容是客户端 - 服务器延迟和PL / pgSQL执行。

不同之处在于必须将WAL同步到磁盘。

如果您使用未记录的表,并且不使用LOCK语句,则不会写入WAL,也不需要在COMMIT时同步任何内容。< / p>

显式表锁会导致写入WAL记录,因此COMMIT仍然需要同步WAL,并且您将失去未记录表的优势。

您可以使用pg_waldump检查WAL文件,然后您将看到写入的事务日志记录。

但我可以使用-DWAL_DEBUG构建的PostgreSQL v11向您展示。

这是我的测试表:

postgres=# \d t
             Unlogged table "public.t"
 Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------
 id     | integer |           |          | 

此处INSERT没有LOCK TABLE

postgres=# SET wal_debug=on;
SET
postgres=# BEGIN;
BEGIN
postgres=# INSERT INTO t VALUES (100);
INSERT 0 1
postgres=# COMMIT;
LOG:  INSERT @ 0/166BFB8:  - Transaction/COMMIT: 2018-05-18 20:34:20.060635+02
STATEMENT:  COMMIT;
COMMIT

有一个提交,但没有WAL刷新。

postgres=# BEGIN;
BEGIN
postgres=# LOCK TABLE t;
LOG:  INSERT @ 0/166C038:  - Standby/LOCK: xid 569 db 13344 rel 16384 
STATEMENT:  LOCK TABLE t;
LOCK TABLE
postgres=# INSERT INTO t VALUES (101);
INSERT 0 1
postgres=# COMMIT;
LOG:  INSERT @ 0/166C138:  - Transaction/COMMIT: 2018-05-18 20:36:15.419081+02
STATEMENT:  COMMIT;
LOG:  xlog flush request 0/166C138; write 0/166BFF0; flush 0/166BFF0
STATEMENT:  COMMIT;
COMMIT

现在我们有一个WAL冲洗,这是昂贵的部分。

您看到写了Standby/LOCK条记录。

解决这个问题的一种方法是将wal_level缩减为minimal,将max_wal_senders缩减为0,然后不必编写这些WAL记录。但是,您无法进行WAL归档和时间点恢复。

另一种解决方法是使用比ACCESS EXCLUSIVE更低的锁定级别。除非你绝对不得不阻止读者,否则应该没问题。