tva
← Insights

DuckDB para Analytics Ad-Hoc: Transformando Milhares de CSVs em um Dashboard

O Amazon Seller Central gera dados em um ritmo que supera as ferramentas da maioria dos analistas’. Relatórios de tráfego, dados de conversão, resumos de saúde do inventário, exportações de desempenho de negócios, detalhamentos de campanhas publicitárias – cada um entregue como um arquivo CSV ou TSV, acumulando ao longo de meses e anos em diretórios contendo milhares de arquivos. A resposta padrão é importar tudo em um banco de dados. Mas, na prática, configurar, manter e consultar uma instância PostgreSQL para o que é fundamentalmente uma carga de trabalho de analytics com leitura intensiva e schema variável introduz mais overhead operacional do que o problema em si justifica.

Construímos um pipeline de relatórios para um vendedor Amazon operando em cinco mercados europeus. Os dados brutos: seis anos de exportações do Seller Central, 4.200 arquivos, cobrindo relatórios de negócios, desempenho de publicidade, snapshots de inventário e razões de taxas FBA. A abordagem inicial – um schema PostgreSQL com scripts ETL – levou três semanas para estabilizar e requeria atenção constante à medida que a Amazon revisava nomes de colunas e estruturas de relatórios entre versões de API. As queries eram rápidas. A manutenção não era.

O DuckDB muda esse cálculo. É um banco de dados analítico embutido – ele roda em processo junto com seu código de análise, não requer servidor, nenhum daemon, nenhuma string de conexão e lê diretamente de arquivos no disco. A interface de consulta é SQL padrão. As características de desempenho são as de um motor columnar otimizado para agregação em escala. Para uma carga de trabalho como esta, o DuckDB não é apenas adequado – é a ferramenta correta.

O Que o DuckDB Realmente É

A distinção que mais importa é armazenamento colunar versus armazenamento por linha. O PostgreSQL organiza dados em linhas: cada campo para um determinado registro é armazenado de forma contígua no disco. Quando você executa SELECT revenue, units_sold FROM orders WHERE marketplace = 'DE', o banco de dados lê cada campo para cada linha, descarta os que você não solicitou e retorna os dois que solicitou. Isso é eficiente para cargas de trabalho transacionais – inserir, atualizar e buscar registros individuais. É amplamente inadequado para queries analíticas que agregam em milhões de linhas enquanto tocam apenas um punhado de colunas.

O DuckDB organiza dados por coluna. Cada valor para revenue é armazenado junto; cada valor para units_sold é armazenado junto. A mesma query lê apenas os dois pedaços de coluna que precisa, ignorando o restante completamente. Em um conjunto de dados com quarenta colunas, esta não é uma otimização menor – reduz o I/O em aproximadamente 95 por cento para queries analíticas típicas. Combinado com execução vetorizada – processando dados em lotes de 1.024 valores por vez usando instruções SIMD de CPU em vez de uma linha por vez – o DuckDB alcança desempenho de consulta em cargas de trabalho analíticas que regularmente supera o que uma instância PostgreSQL bem ajustada pode entregar no mesmo hardware.

The embedded architecture matters equally. There is no network round-trip, no authentication overhead, no connection pool to manage. DuckDB opens a file or directory, builds a query plan, and executes. The binary is under 100MB. It runs on a laptop, inside a Lambda function, or within a Python script invoked from a cron job. For self-hosted analytical pipelines, the operational surface area is close to zero.

SQL Diretamente em Arquivos

The feature that makes DuckDB practical for Seller Central data specifically is glob-based file scanning. A single SQL statement queries thousands of CSVs simultaneously:

SELECT
  date_trunc('month', "Date") AS month,
  SUM("Units Ordered")          AS units,
  SUM("Ordered Product Sales")  AS revenue
FROM read_csv_auto('/data/seller-central/business-reports/*.csv')
GROUP BY 1
ORDER BY 1;

read_csv_auto infers schema from file contents – it samples rows, detects column types, handles different delimiters, and merges schemas across files where column sets differ. For Seller Central data, where Amazon has revised column names at least four times over the past three years, this matters. The query runs against whatever files exist in the directory at execution time, with no import step, no schema migration, and no stale cache to invalidate.

For TSV exports from the advertising console, the same approach applies with an explicit format hint:

FROM read_csv('/data/advertising/*.tsv', delim='	', header=true)

This is not a convenience feature. It is a different mental model for working with file-based data: the file system becomes the database. Schema is inferred, not declared. Queries compose across file boundaries without any preprocessing step. For ad-hoc analysis, where the question changes faster than an ETL pipeline can be updated, this architecture is the correct default.

Características de Desempenho

On our reference dataset – 4,200 files, approximately 2.8GB uncompressed – a full revenue aggregation grouped by marketplace, ASIN, and month completes in 4.1 seconds on a standard laptop (Apple M2, 16GB RAM). The equivalent PostgreSQL query, on imported and indexed data, completes in 2.8 seconds. But that comparison excludes the forty-minute initial import, the schema migrations required each time Amazon changes a column name, and the ongoing ETL maintenance cost. On total operational cost, DuckDB wins decisively for this workload.

If query performance becomes a bottleneck – typically at multi-terabyte scale – DuckDB reads Parquet natively, and converting existing CSV files to Parquet is a one-time operation:

COPY (FROM read_csv_auto('/data/**/*.csv'))
TO '/data/consolidated.parquet'
(FORMAT PARQUET);

Subsequent queries against the Parquet file run 8 to 12 times faster than against the original CSVs. Parquet stores column statistics – minimum and maximum values per row group – which DuckDB uses to skip entire sections of data without reading them. A filter on marketplace = 'DE' over a sorted Parquet file may read less than ten percent of the data on disk. This predicate pushdown is not available against flat CSV files.

Construindo um Dashboard Independente com Chart.js

The output of DuckDB queries is data. The practical question is what to do with it. For internal reporting at small to medium Amazon operations, a standalone HTML file powered by Chart.js is often more useful than a hosted dashboard – no server to run, no credentials to manage, no Superset or Metabase instance to maintain.

The pipeline works in three steps. First, DuckDB exports query results to JSON:

COPY (
  SELECT
    strftime(date_trunc('week', "Date"), '%Y-%m-%d') AS week,
    SUM("Units Ordered")         AS units,
    SUM("Ordered Product Sales") AS revenue
  FROM read_csv_auto('/data/**/*.csv')
  GROUP BY 1 ORDER BY 1
) TO 'weekly.json' (FORMAT JSON, ARRAY true);

Second, a Python script reads those JSON files and embeds the data directly into an HTML template referencing Chart.js via CDN. Third, the HTML file opens in a browser with no web server required.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Seller Dashboard</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
  <canvas id="revenue"></canvas>
  <script>
    const rows = /* JSON_DATA_HERE */;
    new Chart(document.getElementById('revenue'), {
      type: 'line',
      data: {
        labels: rows.map(r => r.week),
        datasets: [{ label: 'Revenue', data: rows.map(r => r.revenue), tension: 0.3 }]
      }
    });
  </script>
</body>
</html>

The result is a self-contained file that can be shared via email, placed on a private S3 bucket, or opened directly from a local directory. For operational teams that need weekly reporting without the overhead of live dashboard infrastructure, this approach is pragmatic and maintainable. The dashboard regenerates by running a shell script: DuckDB queries the CSVs, Python builds the HTML, done. No infrastructure, no recurring costs, no maintenance surface.

Quando o DuckDB Supera o PostgreSQL

DuckDB is not a replacement for PostgreSQL. The comparison is only meaningful when the workload is genuinely analytical – large scans, aggregations, group-bys – and the data is primarily read rather than written. PostgreSQL wins decisively on concurrent writes, referential integrity, row-level access control, and the full operational requirements of a production application. It is the correct choice for a multi-user system where records are inserted, updated, and queried by application code.

DuckDB wins when:

  • The data already exists as files on disk, with no import step planned
  • The schema is not fully known in advance, or changes frequently
  • Queries are ad-hoc and access patterns cannot be predicted in advance
  • The operational overhead of a database server is not justified by project longevity or scale

Amazon Seller Central data satisfies all four criteria precisely. The schema changes with every Seller Central release. The files already exist locally after export. The business questions change week to week depending on what is being optimised. And the alternative – a maintained PostgreSQL ETL pipeline – represents weeks of engineering time for a problem that DuckDB solves in an afternoon.

The practical rule: if you would ordinarily reach for Excel or a Jupyter notebook to analyse this data, reach for DuckDB instead. The SQL is more expressive, the performance is orders of magnitude better for anything beyond a few thousand rows, and the file-based architecture means your data stays where it already is.

Insights Relacionados

Artigos relacionados