Scriptella is a Java ETL tool that describes data flows in XML and SQL. This experiment compares its end-to-end CSV import times with handwritten JDBC, Pandas + SQLAlchemy, and native database loaders.
The reproducible eight-case comparison imports one million rows into PostgreSQL and MariaDB. This repository includes the implementations, raw measurements, independent import verification, and Docker Compose setup.
The goal is to establish a reproducible performance baseline for Scriptella and guide future improvements, starting with a simple CSV import workload.
- Scriptella: declarative CSV parsing and SQL inserts, batch size 1000.
- Handwritten JDBC: a Java baseline using the same database drivers, with Apache Commons CSV for parsing and explicit typed bindings, batch size 1000.
- Pandas + SQLAlchemy: explicit typed CSV chunks inserted in one transaction.
- Native references: PostgreSQL COPY and MariaDB LOAD DATA LOCAL INFILE.
These are specific workflows and settings, not a ranking of CSV loaders. No transformations or database-to-database transfers are tested.
V5 replaces csvsql with Pandas + SQLAlchemy using 10,000-row CSV chunks and
1,000-row inserts, preserving the v4 fixture, schema, transaction boundaries,
warmup and independent verification. PostgreSQL retains
reWriteBatchedInserts=true for both Java implementations. The final eight cases
include six portable workflows and two native bulk-loading references.
MariaDB LOCAL INFILE streams the same client-side fixture without copying it
into the database container. Native loaders have different parsing/error
semantics; see the guide.
Unbatched Scriptella/JDBC are retired: batching is the established baseline for
this workload. There are no unbatched opt-in execution modes.
Keep final eight-case measurements separate from earlier seven-/eleven-case v5
experiments and historical v4 results; their case definitions are incompatible.
See the contender registry for lifecycle decisions. Pandas is retained as a familiar portable reference following the v5 spike; the final measurements are summarized below. No v5 performance claims are based on historical v4 measurements.
Two complete local runs on an Intel Mac with Colima x86_64 (4 CPUs, 6 GiB) imported one million rows through all eight cases using Scriptella 1.6 on 2026-10-26 local time (2026-10-27 UTC).
| Database | Scriptella batch 1000 | JDBC batch 1000 | Pandas + SQLAlchemy | Native reference |
|---|---|---|---|---|
| PostgreSQL | 10.053 s | 7.579 s | 29.106 s | COPY: 2.366 s |
| MariaDB | 9.227 s | 5.622 s | 19.609 s | LOAD DATA LOCAL: 3.039 s |
Pandas took 2.90× and 2.13× Scriptella's time on PostgreSQL and MariaDB, respectively. JDBC was faster than Scriptella in both databases. Native loaders were fastest here and remain separate references with different parsing/error semantics. Every import passed independent row-count and sample-value checks.
The v5 report, individual measurements and reproduction instructions include dependency metadata and limitations. These are two observations on one local environment; no RAM measurements were taken. Historical CI results below come from a different environment and are not a controlled comparison with v5.
One complete GitHub Actions run on 2026-10-21 imported one million rows with Scriptella 1.6 on Ubuntu 24.04:
| Database | Scriptella batch 1000 | JDBC batch 1000 | csvsql chunk 1000 | Native COPY reference |
|---|---|---|---|---|
| PostgreSQL | 7.775 s | 6.320 s | 378.555 s | 1.401 s |
| MariaDB | 6.694 s | 4.465 s | 370.594 s | N/A |
Handwritten JDBC batching was faster than Scriptella; both took less time than csvsql's chunk-1000 import path. Native COPY was fastest on PostgreSQL. Chunking and JDBC batching use different mechanisms.
The full v4 report and evidence include all eleven cases, unbatched results, and dependency metadata. Each import passed independent row-count and sample-value verification before its timing was recorded. These are single observations from one run; CI did not measure RAM. Different GitHub-hosted runners do not establish a controlled comparison with historical runs.
You need Git, a Docker-compatible runtime, and Docker Compose. The container build supplies Java, Maven, Python/Pandas, Scriptella, and JDBC dependencies; a Scriptella source checkout or distribution ZIP is not required.
Clone this repository and enter it:
git clone https://github.com/scriptella/scriptella-benchmarks.git
cd scriptella-benchmarksFirst, smoke-test all eight imports with 2,001-row prefixes, including a final partial batch. This checks correctness without recording benchmark timings. The first invocation also downloads images and builds the benchmark image.
BENCHMARK_COMMAND=smoke SCRIPTELLA_VERSION=1.6 docker compose up --build \
--abort-on-container-exit --exit-code-from benchmarkRun the full million-row comparison with a description of your environment:
ENVIRONMENT_ID=my-machine-docker \
ENVIRONMENT_DESCRIPTION='Describe CPU, architecture and Docker runtime' \
SCRIPTELLA_VERSION=1.6 docker compose up --build --force-recreate \
--abort-on-container-exit --exit-code-from benchmarkHistorical v2 local runs took about 33–35 minutes each; v5 runtime varies by
machine and Docker allocation. Results and diagnostics are saved under
results/run-<timestamp>-<id>/. The command exits nonzero on failure and retains
completed valid measurements and diagnostics.
See the benchmark guide for output files, cleanup, configuration, aggregation, and the complete measurement method.
These are end-to-end workflow timings, including process startup, CSV parsing, type conversion, database writes, and commit. Different parsers, conversion paths, and startup work mean they do not isolate Scriptella's abstraction overhead. This is a single workload; hardware, caches, driver defaults, and fixed case order affect results. Compare implementations within a run. Use repeated runs on a controlled machine to measure changes over time, and keep different benchmark versions and environments separate.
- Benchmark guide: fixture, schema, timing boundaries, driver settings, verification, compatibility rules, and operational details.
- Scriptella ETL example and full benchmark configuration.
- Historical v3 CI results: one complete run before PostgreSQL batch rewriting was enabled.
- Historical v2 local results: two runs, charts, and coarse process-memory observations.
- Historical v2 CI results: one complete run with measurements and dependency metadata.
- Importing a million CSV rows: Scriptella, JDBC, csvsql, and PostgreSQL COPY: the PVR Labs article walking through the historical v2 results.
A separate three-round follow-up
compares pgJDBC reWriteBatchedInserts=false and true at batch size 1000,
using Scriptella 1.6 and handwritten JDBC, with current MariaDB controls.
It retains the v3 fixture, transactions and verification. These measurements
use a separate compatibility identifier and do not replace the v3 results.