[英]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)中的
LOGGED
和UNLOGGED
表上测量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 TABLE
的INSERT
:
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_senders
为0
,然后不必写入这些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.