Skip to content

JDBC backend: isExistsTable lists every table of the database, once per tree, on every backend open #887

Description

@vharseko

Describe the bug

isExistsTable() asks the catalog for every table of the database and looks for a match in Java — no catalog filter, no schema filter, no table name:

// opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/JDBCStorage.java:269
try (final ResultSet rs = con.getMetaData().getTables(null, null, null, new String[]{"TABLE"})) {
    while (rs.next()) {
        if (tree2table.get(treeName).equalsIgnoreCase(rs.getString("TABLE_NAME"))) {

It is called from openTree(createOnDemand) — through AbstractTree.open(), which every tree of the backend goes through — and from deleteTree(). So opening a backend walks the whole catalog once per tree: about 25 times for a stock suffix, and the cost is O(trees × tables in the database) for what ought to be a single indexed lookup. A JDBC backend sharing its database with another application pays for that application's tables too, on every open.

The same two DatabaseMetaData calls of this class — getTables() here and getIndexInfo() in isExistsIndex() — also take no setQueryTimeout, so they are outside the statement bounds of #877/#882 and can only be bounded by the read timeout asked for in #885. Making this one cheap is the fix that matters; the bound is the smaller half.

Impact

The open of a backend, and dsconfig create-backend-index on a running server, are slower than they need to be by a factor that grows with what else lives in the database — a cost that is invisible in a test database and grows quietly in a shared production one.

Expected behavior

  • the table name is passed to getTables() as the pattern, so the driver asks its catalog for one row rather than all of them;
  • the name is passed in the form the catalog stores it — an unquoted identifier is folded to upper case on Oracle and to lower case on PostgreSQL, and a metadata pattern is matched against the stored form — asked of the driver through storesUpperCaseIdentifiers() / storesLowerCaseIdentifiers() rather than by matching its class name, as the dialect switches elsewhere in this class do;
  • the name of the row that comes back is still compared, since _ is a single-character wildcard in a metadata pattern.

Environment

master (5.2.x), all four JDBC dialects (PostgreSQL, MySQL, Oracle, MS SQL Server).

Split out of #885, which keeps the two bounds that live in CachedConnection.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugjdbcperformancePerformance / concurrency / lock-contention work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions