Вставка многих строк вызывает конфликты блокировок с Hibernate и Postgres, оставляя таблицу пустой - PullRequest
0 голосов
/ 28 июня 2019

Мы проводим сравнение некоторых запросов, чтобы увидеть, будут ли они по-прежнему работать надежно для «большого количества» данных.(Если честно, 1 миллион - это не так уж и много, но Postgres здесь уже терпит неудачу, так что, очевидно, так оно и есть).

Наш Java-код для вызова этих запросов выглядит примерно так:

@PersistenceContext
private EntityManager em;
@Resource
private UserTransaction utx;

for (int i = 0; i < 20; i++) {
    this.utx.begin();
    for (int inserts = 0; inserts  < 50_000; inserts ++) {
        em.createNativeQuery(SQL_INSERT).executeUpdate();
    }
    this.utx.commit();


    for (int parameter = 0; parameter  < 25; parameter ++) 
        long time = System.currentTimeMillis();
        Assert.assertNotNull(this.em.createNativeQuery(SQL_SELECT).getResultList());
        System.out.println(i + " iterations \t" + parameter  + "\t" + (System.currentTimeMillis() - time) + "ms");
    }
}

Или с простым JDBC:

Connection connection = //...


for (int i = 0; i < 20; i++) {
    for (int inserts = 0; inserts  < 50_000; inserts ++) {
        try (Statement statement = connection.createStatement();) {
            statement.execute(SQL_INSERT);
        }
    }

    for (int parameter = 0; parameter  < 25; parameter ++) 
        long time = System.currentTimeMillis();

        try (Statement statement = connection.createStatement();) {
            statement.execute(SQL_SELECT);
        }
        System.out.println(i + " iterations \t" + parameter  + "\t" + (System.currentTimeMillis() - time) + "ms");
    }
}

Запрошенные нами запросы были простыми INSERT в таблицу с JSON и INSERT для двух таблиц с примерно 25 строками.SELECT имеет один или два JOIN и довольно прост.Один набор запросов (я должен был анонимизировать SQL, иначе мне бы не разрешили его публиковать):

CREATE TABLE ts1.p (
    id integer NOT NULL,
    CONSTRAINT p_pkey PRIMARY KEY ("id")
);

CREATE TABLE ts1.m(
    pId integer NOT NULL,
    mId character varying(100) NOT NULL,
    a1 character varying(50),
    a2 character varying(50),
    CONSTRAINT m_pkey PRIMARY KEY (pI, mId)
);

CREATE SEQUENCE ts1.seq_p;

/* 
 * SQL_INSERT 
 */

WITH p AS (
    INSERT INTO  ts1.p (id)
           VALUES (nextval('ts1.seq_p'))
    RETURNING id AS pId
)
INSERT INTO ts1.m(pId, mId, a1, a2)
      VALUES ((SELECT pId from p), 'M1', '11', '12'),
             ((SELECT pId from p), 'M2', '13', '14'),
             /*  ... about 20 to 25 rows of values */

/* 
 * SQL_SELECT 
 */

WITH userInput (mId, a1, a2) AS (
  VALUES
    ('M1', '11', '11'),
    ('M2', '12', '15'),
    /* ... about "parameter" rows of values */
)
SELECT m.pId, COUNT(m.a1) AS matches
FROM userInput u
    LEFT JOIN ts1.m m ON (m.mId) = (u.mId)
WHERE (m.a1 IS NOT DISTINCT FROM u.a1) AND
    (m.a2 IS NOT DISTINCT FROM u.a2) OR
    (m.a1 IS NULL AND m.a2 IS NULL)
GROUP BY m.pId

/* plus HAVING, additional WHERE clauses etc. according to the use case, but that just speeds up the query */

При выполнении мы получаем следующий вывод (значения должны постоянно растии линейно):

271ms
414ms
602ms
820ms
995ms
1192ms
1396ms
1594ms
1808ms
1959ms
110ms
33ms
14ms
10ms
11ms
10ms
21ms
8ms
13ms
10ms

Как видите, после некоторого значения (обычно от 300 000 до 500 000 вставок) время, необходимое для запроса, значительно уменьшается.К сожалению, мы не можем на самом деле отладить, каков результат на тот момент (кроме того, что он не нулевой), но мы предполагаем, что это пустой список, потому что таблицы базы данных пусты.

Позвольте мне повторить это: После полумиллиона INSERTS Постгрес очищает таблицы.

Конечно, это вообще неприемлемо.

Мы пробовали разные запросы, все от легкой до средней сложности, и все создали это поведение, поэтому мы предполагаем, что это не запросы.

Мы думали, что, возможно, последовательность вернула слишком большое значение длястолбец integer, поэтому мы отбросили и воссоздали последовательность.

Как только появилось это исключение:

org.postgresql.util.PSQLException : FEHLER: Verklemmung (Deadlock) entdeckt
  Detail: Prozess 1620 wartet auf AccessExclusiveLock-Sperre auf Relation 2001098 der Datenbank 1937678; blockiert von Prozess 2480.

, которое я совершенно не могу перевести.Я думаю, это что-то вроде:

org.postgresql.util.PSQLException : ERROR: Jamming? Clamping? Constipation? (Deadlock) found

Но я не думаю, что эта ошибка имеет какое-либо отношение к очистке таблицы.Мы только что проверили не ту базу данных, поэтому несколько запросов были запущены для одной и той же таблицы.Обычно у нас есть одна база данных для каждого теста производительности.

Конечно, важно выяснить, в чем заключается ошибка, чтобы мы могли решить, есть ли риск для наших клиентов потерять свои данные (потому что, опять же, из-за ошибкибаза данных опустошает некоторые таблицы по своему выбору).

Версия Postgres: PostgreSQL 10.6, compiled by Visual C++ build 1800, 64-bit

Мы тоже попробовали PostgreSQL 9.6.11, compiled by Visual C++ build 1800, 64-bit.И у нас никогда не было той же проблемы (хотя это может быть просто удача, поскольку она не воспроизводима на 100%).

У вас есть идеи, что это за ошибка?Или как мы могли бы отладить это?Весь тест производительности выполняется в течение часа, поэтому немедленной обратной связи нет.

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