[英]Postgres inconsistent insertion performance
我使用 JDBC 插入 postgres。 由於某種原因,運行之間的性能似乎有所不同。 我觀察到它在 2 個性能級別之間切換,“快”和慢 10 倍左右。
我已經用 postgres 14.2、14.3 和 13.6 測試了這個問題。 似乎它與所有版本都相關。
這種行為可能是什么原因?
MRE(Java 17):
package test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
public class App {
private static final Logger log = LoggerFactory.getLogger(App.class);
public static void main(String[] args) throws Exception {
Class.forName("org.postgresql.Driver");
try (Connection connection = DriverManager.getConnection("jdbc:postgresql://172.17.0.3:5432/postgres", "postgres", "postgres")) {
connection.setAutoCommit(false);
var uploadedCount = 0;
final var insertA = connection.prepareStatement("insert into A(AA) values(?)");
final var insertB = connection.prepareStatement("insert into B(BA, BB) values(?, ?)");
final var startTime = System.currentTimeMillis();
var timeA = 0;
var timeB = 0;
var batchSize = 0;
var batchesCount = 0;
for (long i = 0; i < 16_384; i++) {
insertA.setObject(1, i);
insertA.addBatch();
insertB.setObject(1, i);
insertB.setObject(2, i);
insertB.addBatch();
batchSize++;
if (batchSize == 32) {
var start = System.currentTimeMillis();
insertA.executeBatch();
timeA += System.currentTimeMillis() - start;
start = System.currentTimeMillis();
insertB.executeBatch();
timeB += System.currentTimeMillis() - start;
uploadedCount += batchSize * 2;
batchSize = 0;
batchesCount++;
if (batchesCount % 256 == 0) {
log.info("INSERT A CUMULATIVE TIME: {}", timeA);
log.info("INSERT B CUMULATIVE TIME: {}", timeB);
log.info("ROWS PER SEC: {}", uploadedCount * 1000L / (System.currentTimeMillis() - startTime));
}
}
}
}
}
}
MRE架構:
CREATE TABLE A (AA BIGINT NOT NULL, CONSTRAINT PK_AA PRIMARY KEY (AA));
CREATE TABLE B (BA BIGINT NOT NULL, BB BIGINT NOT NULL, CONSTRAINT PK_BA_BB PRIMARY KEY (BA, BB));
ALTER TABLE B ADD CONSTRAINT FK_BA_A FOREIGN KEY (BA) REFERENCES A (AA);
ALTER TABLE B ADD CONSTRAINT FK_BB_A FOREIGN KEY (BB) REFERENCES A (AA);
MRE 慢速運行示例日志:
2022-05-31 14:50:45 I main App INSERT A CUMULATIVE TIME: 108
2022-05-31 14:50:45 I main App INSERT B CUMULATIVE TIME: 4395
2022-05-31 14:50:45 I main App ROWS PER SEC: 3623
2022-05-31 14:50:58 I main App INSERT A CUMULATIVE TIME: 197
2022-05-31 14:50:58 I main App INSERT B CUMULATIVE TIME: 17046
2022-05-31 14:50:58 I main App ROWS PER SEC: 1896
MRE 快速運行示例日志:
2022-05-31 14:51:02 I main App INSERT A CUMULATIVE TIME: 100
2022-05-31 14:51:02 I main App INSERT B CUMULATIVE TIME: 269
2022-05-31 14:51:02 I main App ROWS PER SEC: 43115
2022-05-31 14:51:03 I main App INSERT A CUMULATIVE TIME: 177
2022-05-31 14:51:03 I main App INSERT B CUMULATIVE TIME: 509
2022-05-31 14:51:03 I main App ROWS PER SEC: 46811
我沒有觀察到模式的現象:
CREATE TABLE A (AA BIGINT NOT NULL, CONSTRAINT PK_AA PRIMARY KEY (AA));
CREATE TABLE B (BA BIGINT NOT NULL, CONSTRAINT PK_BA PRIMARY KEY (BA));
ALTER TABLE B ADD CONSTRAINT FK_BA_A FOREIGN KEY (BA) REFERENCES A (AA);
你的程序從不提交任何東西,所以每次你運行它時,表都是空的。 他們是否根本沒有行,或者只是沒有已提交的行但有許多正在進行/中止的行,以及計划者是否知道這一點,將取決於上次運行真空或分析的時間。
如果表“a”開始時真的是空的,那么規划器會認為驗證約束的最有效方法是對“a”進行 seq 掃描,而不是索引掃描。 這開始很好,但隨着它挖掘越來越多的自己的垃圾而變得越來越慢,因此變得越來越慢。
我可以通過在第一個會話仍在運行時手動ANALYZE a,b
在單獨的會話中將其啟動到快速模式(盡管這是否有效可能取決於版本——我認為在舊版本中,一個會話的 ANALYZE 會忽略另一個會話未提交的行)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.