我们正在对一些查询进行基准测试,以查看它们是否仍然可以对“大量”数据可靠地工作。 (说实话,一百万并不算多,但是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插入)之后,查询所需的时间大大减少。遗憾的是,我们无法真正调试当时的结果(除了它不是null之外),但是我们假定它是一个空列表,因为数据库表是空的。
让我重复一遍:在INSERTS
经过一百万次之后,Postgres清除了表。
当然这是完全不能接受的。
我们尝试了各种不同的查询,所有这些查询都从中级到中级,并且都产生了这种行为,因此我们假设这不是查询。
我们认为该序列可能返回的值对于列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%可重复的)。
您知道错误是什么吗?或者我们如何调试它?整个基准测试运行一个小时,因此没有即时反馈。