簡體   English   中英

Postgres 插入性能不一致

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM