Сравнение производительности таблиц PostgreSQL LOGGED и UNLOGGED с использованием LOCK TABLE - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь измерить UPDATE скорость на LOGGED и UNLOGGED таблицах в PostgreSQL (10.3).Я хочу использовать LOCK TABLE, чтобы другие приложения не мешали друг другу.

Если UPDATE выполняется без использования LOCK TABLE, я получаю ~ 1K для таблицы LOGGED, ~ 4K для таблицы UNLOGGED.

Если 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 голосов
/ 18 мая 2018

Здесь вы часто измеряете задержку клиент-сервер и выполнение PL / pgSQL.

Разница вызвана необходимостью синхронизации WAL с диском.

Если вы используетене заблокированная таблица, и вы не используете оператор LOCK, WAL не записывается и ничего не должно синхронизироваться в COMMIT время.

Явные блокировки таблицы приводят к тому, что запись WAL будетнаписано, поэтому COMMIT все равно придется синхронизировать WAL, и вы потеряете преимущество, которое у вас есть от незарегистрированной таблицы.

Вы можете использовать pg_waldump для проверки файлов WAL, тогда вы увидите, какой журнал транзакцийзаписи записаны.

Но я могу показать это вам с моим PostgreSQL v11, построенным с -DWAL_DEBUG.

Это моя тестовая таблица:

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.Это должно быть хорошо, если вам абсолютно не нужно блокировать читателей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...