Repository navigation
perf(plugins): list every schema's tables in one query on Oracle, Dameng, HANA, Trino, CockroachDB and Redshift - #3708
Conversation
…eng, HANA, Trino, CockroachDB and Redshift
# Conflicts: # apple/Packages/TableProOracle/Sources/TableProOracleCore/OracleSchemaQueries.swift
J2TeamNNL
left a comment
There was a problem hiding this comment.
Automated review: 7 findings, none a confirmed crash.
| return merged.sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending } | ||
| } | ||
|
|
||
| func fetchTables(inSchemas schemas: [String]) async throws -> [PluginTableInfo]? { |
There was a problem hiding this comment.
Redshift's set read appends external (Spectrum) tables unsorted, while the single-schema read merges them and re-sorts by name. Consumers relying on name order within a schema see different ordering depending on which path ran.
| func fetchTables(inSchemas schemas: [String]) async throws -> [PluginTableInfo]? { | ||
| guard !schemas.isEmpty else { return [] } | ||
| let result = try await execute(query: RedshiftTableCatalog.listingQuery(inSchemas: schemas)) | ||
| var tables = result.rows.compactMap { RedshiftTableCatalog.table(fromListingRow: $0.map(\.asText)) } |
There was a problem hiding this comment.
One svv_external_tables query per external schema, plus an O(n) tables.lazy.filter rescan of the growing list each iteration (quadratic on a 50k-table catalog). Group local names by schema once up front.
| """ | ||
| } | ||
|
|
||
| static func tables(inSchemas schemas: [String]) -> String { |
There was a problem hiding this comment.
tables(inSchemas:) builds IN () for an empty list, which does not parse. Only the caller's guard prevents it. Trino and Postgres use a membership(...) helper that emits false for an empty list.
|
|
||
| func fetchTables(inSchemas schemas: [String]) async throws -> [PluginTableInfo]? { | ||
| // DM8 follows Oracle here, so each statement stays under Oracle's 1,000-expression IN limit. | ||
| let chunkSize = 1_000 |
There was a problem hiding this comment.
Hard-coded chunkSize = 1_000 with each owner bound twice means 2,000 bind parameters per statement, unverified against DM's cap. A failure falls back to per-schema queries, losing the gain on large catalogs. Also duplicates OracleSchemaQueries.maxOwnersPerTableListing.
| throw CancellationError() | ||
| } catch let error as DatabaseError { | ||
| throw error | ||
| } catch { |
There was a problem hiding this comment.
Any non-DatabaseError from the set read (timeout, resource error) falls back to N sequential per-schema reads, multiplying load on an already struggling server on large catalogs.
| } | ||
|
|
||
| private func materializedViews(catalog: String, schemas: [String]) async -> Set<TrinoRelationKey> { | ||
| let sql = TrinoIntrospectionSQL.listMaterializedViews(catalog: catalog, inSchemas: schemas, flavor: flavor) |
There was a problem hiding this comment.
try? swallows task cancellation, then the per-schema fallback loop runs without Task.checkCancellation(), so work continues after the user cancels.
| """ | ||
| } | ||
|
|
||
| public static func table(fromRow row: [String?]) -> PluginTableInfo? { |
There was a problem hiding this comment.
table(fromRow:) is a near-copy of RedshiftTableCatalog.table(fromListingRow:) and has already drifted (Cockroach uppercases the type before contains("VIEW"), Redshift does not).
| } | ||
|
|
||
| func fetchTables(inSchemas schemas: [String]) async throws -> [PluginTableInfo]? { | ||
| var tables: [PluginTableInfo] = [] |
There was a problem hiding this comment.
Chunks run sequentially and the result is only ordered within each 1,000-owner chunk, not globally by owner/name as the query's ORDER BY implies.
|
Review findings from the earlier review, handled in J2TeamNNL@d256453. Fixed (7):
Skipped (1):
Not built locally (no Xcode); the edited files parse with swiftc -parse. swiftlint did not run (sourcekit missing). To take it: |
Summary
CatalogTableListing. With no all-schema answer from the driver it went straight to one query per schema. It now lists the schemas, drops the system ones, and asksfetchTables(inSchemas:)once. Per schema only when the driver has no set read, or the set read fails for a reason other than a lost connection.fetchTables(inSchemas:)on Oracle, Dameng, SAP HANA, Trino, CockroachDB and Redshift: the per-schema query widened toIN (...), schema projected on every row. Oracle and Dameng split at 1,000 names (ORA-01795). Redshift still adds external tables per external schema. Trino falls back to per-schema materialized-view reads when the combined one fails.x'́) was left undoubled: PostgreSQL 17 rejects that listing with a syntax error, and in a set read one such schema name would fail every schema.apple/scripts/probes/build-large-catalog-fixtures.shbuilds the Measure the sidebar, Open Quickly and autocomplete on 100 schemas and 50,000 tables #3661 fixtures: PostgreSQL 100 schemas x 500 tables, Oracle the same in agvenzl/oracle-freecontainer, MySQL one database of 50,000 tables.TableProTrinoCoreTeststarget in TableProCore.Server time for the other schemas' tables on the PostgreSQL fixture, PostgreSQL 17.11 local, information_schema query CockroachDB and Redshift use, 3 runs on a loaded machine:
Test plan
CatalogTableListingTests: every schema through the set read (schema list, then one read with the excluded schemas left out); a failed set read falls back per schema and names only the failing schema; a lost connection in the set read fails the listing without per-schema reads.TableProOracleCoreTests(swift test): 47/47 pass, including the set query, the 1,000-name split, the owner column, the combining-mark escape and SYS qualification of the new query.TableProTrinoCoreTests(swift test): 3/3 pass.PostgreSQLDriverTests: Cockroach and Redshift set queries and rows, combining-mark quoting; new builders added to the literal-quoting matrix.swiftc -typecheckof the PostgreSQL, Oracle, Trino, HANA and Dameng plugin sources and the changed PostgreSQL tests passed. CI covers the rest.Not in this PR
FROMandschema.; resident memory) and their budgets. They need a quiet machine and the three fixtures.SHOW OBJECTS IN DATABASEcaps at 10,000 rows (same reason as feat(plugins): list every schema's tables in one query on SQL Server and DuckDB #3096).INFO FOR DBper database), R2 SQL (SHOW TABLESper namespace) have no single catalog read. Spanner could take one but needs a live instance for its two dialects.Docs: TableProApp/docs#67
Refs #3661