Skip to content

perf(go): optimize GetObjects by reading SHOW results directly#105

Open
zeroshade wants to merge 3 commits intomainfrom
optimize-getobjects
Open

perf(go): optimize GetObjects by reading SHOW results directly#105
zeroshade wants to merge 3 commits intomainfrom
optimize-getobjects

Conversation

@zeroshade
Copy link
Copy Markdown
Contributor

Summary

  • Reduce Snowflake round-trips for GetObjects at ObjectDepthTables and ObjectDepthDBSchemas when catalog is specific (non-wildcard)
  • New direct path reads SHOW TERSE rows via driver.Rows and builds the GetObjectsInfo tree in Go, instead of collecting queryIDs and running complex SQL templates that re-read results through RESULT_SCAN joins
  • Wildcard-catalog queries are unaffected and fall through to the existing SQL template path

Motivation

Benchmark comparison (report) between the ADBC ODBC bridge and the official Snowflake ODBC driver showed SQLTables was 2.06x slower. The root cause: GetObjects(ObjectDepthTables) executed 4 Snowflake queries (3 parallel SHOW TERSE + 1 complex SQL joining them via RESULT_SCAN) where the official driver uses essentially 1 query.

Query count reductions

Scenario Before After
Specific catalog + specific schema (ObjectDepthTables) 4 queries 1 query
Specific catalog + wildcard schema (ObjectDepthTables) 4 queries 2 queries
Specific catalog (ObjectDepthDBSchemas) 3 queries 1 query
Wildcard catalog (any depth) Unchanged Unchanged

Changes

  • go/get_objects_direct.go (new): Optimized GetObjects implementations that execute SHOW TERSE commands and read rows directly, building the result tree in Go via driverbase.BuildGetObjectsRecordReader.
  • go/connection.go: Added fast-path call in GetObjects() before the existing SQL template path. Falls through when the direct path is not applicable.

Reduce Snowflake round-trips for GetObjects at ObjectDepthTables and
ObjectDepthDBSchemas when catalog is specific (non-wildcard). Instead
of executing SHOW TERSE commands only to collect queryIDs then running
a complex SQL template that re-reads those results via RESULT_SCAN
joins, the new direct path reads SHOW rows via driver.Rows and builds
the GetObjectsInfo tree in Go.

Query count reductions:
- Specific catalog + schema (Tables depth): 4 -> 1
- Specific catalog + wildcard schema (Tables depth): 4 -> 2
- Specific catalog (DBSchemas depth): 3 -> 1
- Wildcard catalog: unchanged (falls through to existing path)
@@ -0,0 +1,382 @@
// Copyright (c) 2025 ADBC Drivers Contributors
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Copyright (c) 2025 ADBC Drivers Contributors
// Copyright (c) 2026 ADBC Drivers Contributors

Comment on lines +338 to +347
cols := rows.Columns()
nameIdx, dbIdx := -1, -1
for i, col := range cols {
switch col {
case "name":
nameIdx = i
case "database_name":
dbIdx = i
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the column order not fixed?

return readSchemaEntries(rows)
}

func readSchemaEntries(rows driver.Rows) ([]schemaEntry, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only ever used in one place; just consolidate the two functions?

rows, err := c.cn.QueryContext(ctx, query, nil)
if err != nil {
var sfErr *gosnowflake.SnowflakeError
if errors.As(err, &sfErr) && sfErr.Number == 2043 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is error 2043?

}

// execShowSchemas executes a SHOW TERSE SCHEMAS command and reads the results directly.
func (c *connectionImpl) execShowSchemas(ctx context.Context, pattern *string, suffix string) (entries []schemaEntry, err error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Why are the results named when we never use that?)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants