GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — perf(telemetry): serialize telemetry events without dataclasses.asdict by vuanhphung · Pull Request #1040 · databricks/databricks-sql-python

Conversation

@vuanhphung

@vuanhphung vuanhphung commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator

What type of PR is this?

  • Other (performance)

Description

Every statement exports a telemetry event, and the thread that fills a batch (every 100th statement) serializes all of its events inline. JsonSerializableMixin.to_json used dataclasses.asdict, which recursively deep-copies the whole event, about 65 nodes with the system configuration and connection parameters. It took ~64 us per event, and flushing 100 events held the calling thread for ~6.8 ms.

With 64 threads running SELECT 1 against a mock warehouse, py-spy --gil put telemetry export at ~15% of worker GIL time, ~12% of it in asdict. Turning telemetry off raised throughput 16% (983 → 1,137 statements/s), so most of that overhead is serialization.

to_json now walks dataclass fields directly, using cached field names, and drops None fields the way the old dict_factory did. It no longer deep-copies leaves and reuses one EnumEncoder instead of building one per call. The JSON is byte-identical: ~19 us per event (3.4x faster), and a 100-event flush takes ~2.3 ms.

How is this tested?

  • Unit tests
  • E2E Tests
  • Manually

tests/unit/test_telemetry_serialization.py keeps the previous serializer (json.dumps(asdict(..., dict_factory=...), cls=EnumEncoder)) as the oracle and asserts byte-for-byte equality over:

  • every event the client exports: connection, failure, and latency events for each statement type and result format;
  • the full flush payload;
  • every telemetry model, fully populated and with all optional fields None;
  • nested structs and containers holding None, enums and dataclasses;
  • non-ASCII strings, control characters and lone surrogates;
  • floats including -0.0, subnormals, inf and nan;
  • 300 seeded random events.

It also checks that unserializable values raise TypeError like before. Six deliberately broken serializers (dropping falsy values, dropping None in lists, ensure_ascii=False, sorted keys, compact separators, enum names instead of values) each fail the suite. The full unit suite passes. The live telemetry e2e tests (test_telemetry_e2e.py, test_concurrent_telemetry.py) pass against a warehouse, so the endpoint accepts the payloads.

Performance: main vs this branch in fresh, interleaved processes, median of 5 runs. Mock Thrift server replaying a captured SELECT 1 reply with 50 ms RTT, one connection per thread, cursor per statement, telemetry on. One thread is RTT-bound and unchanged; a re-run at 64 threads with fetchall gave +5.0%.

Threads Fetch Statements/s p50 (ms) p99 (ms) CPU/statement (ms)
16 fetchall_arrow 301 → 304 52.1 → 52.0 66.7 → 59.0 0.94 → 0.86
64 fetchall_arrow 985 → 1052 62.4 → 59.0 93.0 → 86.4 1.07 → 1.03
200 fetchall_arrow 1071 → 1137 176 → 167 357 → 322 1.16 → 1.10
64 fetchall 692 → 739 90.2 → 84.6 138.7 → 125.5 1.72 → 1.60
200 fetchall 687 → 729 283 → 265 382 → 370 1.76 → 1.65

Related Tickets & Documents

None.

This pull request and its description were written by Isaac.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vuanhphung Isaac
perf(telemetry): serialize telemetry events without dataclasses.asdict
104f068
Every statement exports a telemetry event, and asdict's recursive deep
copies made to_json about 64 us per event; the thread that fills a batch
also serializes all 100 events inline. A field-name walk that drops None
fields gives byte-identical JSON in about 19 us.

Tests compare the output byte for byte with the previous asdict-based
serializer over every event the client exports, the flush payload, all
model types, and seeded random events with non-ASCII strings and floats.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 11:27 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 11:27 — with GitHub Actions Inactive
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

✅ No issues identified by the review bot.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vuanhphung vuanhphung mentioned this pull request Nov 12, 2026
perf(thrift): skip unsafe payload log records nothing can receive #1041
Open
3 tasks done

This branch was previously deployed

1 inactive deployment
azure-prod — 104f068a Deployed Nov 12, 2026 by vuanhphung via review #636
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@peco-review-bot peco-review-bot[bot] peco-review-bot[bot] approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@vuanhphung
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.