简体   繁体   English

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

[英]PostgreSQL LOGGED and UNLOGGED table performance comparison with LOCK TABLE usage

I am trying to measure UPDATE speed on LOGGED and UNLOGGED tables in PostgreSQL(10.3). 我正在尝试在PostgreSQL(10.3)中的LOGGEDUNLOGGED表上测量UPDATE速度。 I want to use LOCK TABLE to prevent other applications from interfering with each other. 我想使用LOCK TABLE来防止其他应用程序相互干扰。

If UPDATE is performed without using LOCK TABLE , I get ~ 1K for the LOGGED table, ~ 4K for the UNLOGGED table. 如果在不使用LOCK TABLE情况下执行UPDATE ,则LOGGED表为UNLOGGED表为UNLOGGED

If UPDATE is performed using LOCK TABLE , the results are the same for both table types. 如果使用LOCK TABLE执行UPDATE ,则两种表类型的结果都相同。

Why does LOCK TABLE return the same result in both table types? 为什么在两种表类型中LOCK TABLE返回相同的结果?

My PL/pgSQL function: 我的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;

My Java code: 我的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);
}   

A lot of what you are measuring here is client-server latency and PL/pgSQL execution. 您在此处测量的很多内容是客户端服务器延迟和PL / pgSQL执行。

The difference is caused by the necessity to sync WAL to disk. 造成这种差异的原因是必须将WAL同步到磁盘。

If you use an unlogged table, and you don't use the LOCK statement, no WAL is written, and nothing has to be sync'ed at COMMIT time. 如果使用未记录的表,并且不使用LOCK语句,则不会写入WAL,并且在COMMIT时无需同步任何内容。

Explicit table locks cause a WAL record to be written, so COMMIT still has to sync WAL, and you lose the advantage you have from an unlogged table. 显式表锁导致写入WAL记录,因此COMMIT仍然必须同步WAL,并且您将失去从未记录表中获得的优势。

You can use pg_waldump to examine the WAL files, then you'll see what transaction log records are written. 您可以使用pg_waldump检查WAL文件,然后您将看到写入了哪些事务日志记录。

But I can show it to you with my PostgreSQL v11, built with -DWAL_DEBUG . 但是我可以使用-DWAL_DEBUG构建的PostgreSQL v11向您-DWAL_DEBUG

This is my test table: 这是我的测试表:

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

Here an INSERT without LOCK TABLE : 这里是没有LOCK TABLEINSERT

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

There was a commit, but no WAL flush. 有一个提交,但没有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

Now we have a WAL flush, and that is the expensive part. 现在我们有了WAL刷新,这是昂贵的部分。

You see that a Standby/LOCK record was written. 您会看到一个Standby/LOCK记录已写入。

One way to get around that is to reduce wal_level to minimal and max_wal_senders to 0 , then these WAL records don't have to be written. 解决该问题的一种方法是将wal_level减小为minimal ,将max_wal_senders0 ,然后不必写入这些WAL记录。 But then you cannot have WAL archiving and point-in-time recovery. 但是,您将无法进行WAL归档和时间点恢复。

The other workaround is to use a lower lock level than ACCESS EXCLUSIVE . 另一个解决方法是使用比ACCESS EXCLUSIVE更低的锁定级别。 That should be fine unless you absolutely have to block readers. 除非您绝对必须阻止读者,否则应该没问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM