Diario
Secciones
Ajustes de lectura
Voz natural grabada para este curso, la misma en todos los navegadores.
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Progreso
Sección titulada «Progreso»- Instantánea de los datos: 125 ejecuciones y 315 jobs de este repositorio
- CI: el SQL de cada lección comparado con su salida esperada en tres sistemas operativos
- Lección 1: primeras consultas
- Lección 2: Friendly SQL
- Lección 3: datos anidados
- Lección 4: archivos
- Lección 5: DuckDB desde C#
- Lección 6: DuckDB desde Java
- Lección 7: rendimiento
- Lección 8: persistencia, transacciones y concurrencia
DuckDB 1.5.5, su driver de .NET y su driver de JDBC son software de otros. Dos filas de abajo pierden datos sin decirlo: por eso la columna Estado las separa de las que describen un comportamiento documentado con el que choca una costumbre de C# o Java. Nada se ha reportado aguas arriba.
| Esperado | Lo que pasa | Dónde | Medición | Estado |
|---|---|---|---|---|
DuckDB.NET rellena una clase desde un STRUCT por nombre de propiedad |
Ignora las mayúsculas pero no los guiones bajos: StartedAt conserva su valor por defecto sin decir nada, mientras Started_At sí se rellena |
DuckDB.NET 1.5.5 | Silencioso, ninguna excepción. Un record posicional en cambio lanza MissingMethodException |
Reproducido, no reportado 2026-09-14 |
Un TIMESTAMPTZ sobrevive a una ida y vuelta por el driver |
Vuelve como DateTime con el valor UTC y un Kind Unspecified, así que ToUniversalTime lo desplaza una segunda vez. En Java es un OffsetDateTime en la zona de la JVM, diga lo que diga SET TimeZone |
DuckDB.NET 1.5.5, duckdb_jdbc 1.5.5.1 | Valores equivocados, en silencio, en ambos drivers | Reproducido, no reportado 2026-09-14 |
| Una cadena de varias sentencias es atómica, como la página de transacciones de DuckDB describe una transacción implícita | No lo es: las dos primeras filas se quedaron cuando la tercera sentencia falló, en la CLI y por JDBC | CLI de DuckDB 1.5.5 y duckdb_jdbc | 2 de 3 filas conservadas, tanto con -c "a; b; c" como con statement.execute("a; b; c"). Un COMMIT tras un error no imprime nada y deshace |
Reproducido; la documentación y el comportamiento se contradicen 2026-09-14 |
Una consulta fallida deja el Statement utilizable |
El statement queda cerrado: un bucle que captura el error y sigue falla en todas las sentencias posteriores | duckdb_jdbc 1.5.5.1 | Statement was closed |
Reproducido, no reportado 2026-09-14 |
| El sniffer de CSV avisa de una columna que no supo analizar | Lee en silencio 13/09/2026 15:53 como VARCHAR, y un timestampformat equivocado también; solo un tipo explícito lo hace fallar |
DuckDB 1.5.5 | Toda comparación de fechas posterior pasa a ser comparación de cadenas | Reproducido; las palabras del diario: «This isn’t an error» 2026-09-14 |
| Un glob sobre archivos de formas distintas avisa o falla | FROM 'data/*.json' fusiona los runs y los jobs en una tabla sin decir nada |
DuckDB 1.5.5 | 20 columnas sacadas de dos formas sin relación | Reproducido, no reportado 2026-09-14 |
El approx_unique de SUMMARIZE cuenta los valores distintos |
Cuenta de más y de menos | CLI de DuckDB 1.5.5 | 131 para 125 identificadores de ejecución, 17 para 21 nombres de workflow | Por diseño: HyperLogLog cambia exactitud por memoria constante 2026-09-14 |
labels[0] es un error |
Devuelve NULL, igual que cualquier índice pasado el final |
DuckDB 1.5.5 | Ningún error | Por diseño: las listas empiezan en 1. Una costumbre de C# o Java que falla en silencio 2026-09-14 |
| El escritor de Parquet produce los mismos bytes para los mismos datos | No — escribe con varios hilos | escritura Parquet de DuckDB 1.5.5 | 119 021 205 y luego 119 392 814 bytes en local para un archivo de 11 millones de filas; 118 714 412 a 119 120 557 en los ejecutores. En el primer push el script de la lección 4 falló solo en macOS: 8 fragmentos de columna diferían de 1 a 6 bytes en total_compressed_size |
Reproducido; un fallo real de CI, sorteado comparando num_values 2026-09-14 |
| Predicados de fecha equivalentes obtienen planes equivalentes | started_at::DATE = … y date_trunc('day', started_at) = … se reescriben en un rango que salta grupos de filas; strftime(started_at, …) = … sigue siendo una expresión y lee todas las filas |
optimizador de DuckDB 1.5.5 | 0,47 s frente a 0,003 s en el archivo ordenado | Reproducido; una reescritura realmente perdida 2026-09-14 |
Una ordenación que no cabe en memory_limit se vuelca a disco |
Falla con 4 hilos y funciona con 1, y el COPY fallido deja un archivo parcial |
DuckDB 1.5.5 | 11 M de filas con memory_limit = '100MB'; 6,3 a 9,9 s en el caso de un hilo |
Reproducido, dependiente del número de hilos 2026-09-14 |
| Un proceso de solo lectura puede abrir un archivo que otro tiene | Un proceso que tiene el archivo bloquea a todos los demás, los de solo lectura incluidos, con un mensaje distinto en cada sistema | DuckDB 1.5.5 | Tres sistemas, tres mensajes; Linux y macOS añaden una pista sobre -readonly que Windows no da |
Reproducido; por diseño 2026-09-14 |
| El jar de JDBC y el paquete de .NET llevan lo que la plataforma necesita | El jar pesa 85 MB, con cuatro bibliotecas nativas y ninguna build de Windows sobre Arm | duckdb_jdbc 1.5.5.1, DuckDB.NET 1.5.5 | DuckDB.NET.Data.Full pesa 420 MB en la caché de NuGet, 316 MB en bin/Debug, 69 MB publicado solo para linux-x64 |
Medido; la ausencia de build win-arm64 es una carencia real 2026-09-14 |
| El script de instalación de una línea cubre los tres sistemas | `curl -fsSL https://install.duckdb.org | sh` no admite Windows | install.duckdb.org | El workflow descarga duckdb_cli-windows-amd64.zip en su lugar |
| Un lote de JDBC es más rápido que sentencias una a una | No lo era | duckdb_jdbc 1.5.5.1, en CI | 690 ms a 2,4 s para 10 000 filas, frente a 226 a 331 ms para 1 000 000 de filas con el appender de C# | Medido, causa no investigada 2026-09-14 |
Experimentos
Sección titulada «Experimentos»Cuatro preguntas que el curso se hizo antes de medir. Ninguna es una hipótesis que el autor inventara y luego pusiera a prueba — dos se apoyan en documentación leída de antemano, una en un valor leído del propio archivo — y la tabla lo dice en lugar de disfrazarlas. La tercera es la que volvió refutada.
| Pregunta | Hipótesis | Resultado | Veredicto | Dónde |
|---|---|---|---|---|
¿Puede la CI comparar planes EXPLAIN entre tres ejecutores? |
El diario plantea la pregunta y saca su conclusión de la respuesta; ninguna predicción escrita | La salida no depende del número de hilos, y las estimaciones fueron las mismas en los tres ejecutores | Confirmada: los planes son comparables | 2026-09-14 |
| ¿Puede un DuckDB más antiguo leer un archivo escrito por la 1.5.5? | La etiqueta storage_version=v1.0.0+ del propio archivo, leída antes de la prueba |
La CLI 1.0.0 leyó los archivos escritos por defecto. Con STORAGE_VERSION 'v1.5.0' los rechazó: version number 68, can only read 64 |
Confirmada, con su control negativo | 2026-09-14 |
| ¿Es atómica una cadena de varias sentencias? | Sí — la página de transacciones de DuckDB describe una transacción implícita. Un supuesto documentado y citado antes de la prueba | -c "a; b; c" y statement.execute("a; b; c") conservaron ambos las dos primeras filas cuando la tercera falló |
Refutada | 2026-09-14 |
| ¿Se cumple la predicción del plan en tiempo real? | El plan dice que ::DATE y date_trunc saltan grupos de filas y que strftime no; la lección 7 lee los planes y luego mide lo que predicen |
0,47 s frente a 0,003 s en el archivo ordenado | Confirmada | 2026-09-14 |
2026-09-14 — Los datos
Sección titulada «2026-09-14 — Los datos»runs.json:gh run list --limit 1000 --json databaseId,workflowName,event,status,conclusion,createdAt,updatedAt,startedAt,headBranch,headSha,attempt, exportado hacia las 14:04 UTC. 125 ejecuciones, la más antigua del 2026-09-13 a las 15:53.jobs.json: una llamada por ejecución arepos/spareilleux/learn/actions/runs/{id}/jobs?per_page=100, conservando 11 campos de cada job y 5 de cada step. 315 jobs para 121 ejecuciones: 4 ejecuciones nunca tuvieron ningún job.- El endpoint de jobs solo devuelve el último intento: 4 jobs para la ejecución que se intentó tres veces, 12 con
?filter=all. Me di cuenta al escribir la lección 3; la instantánea se queda como está.
2026-09-14 — Instalar DuckDB
Sección titulada «2026-09-14 — Instalar DuckDB»- En local,
wingettenía instalado DuckDB 1.5.3 (DuckDB.cli), con la 1.5.5 disponible. El curso usa la 1.5.5, descomprimida de la release de GitHub. - CI en Linux y macOS:
curl -fsSL https://install.duckdb.org | sh→Successfully installed DuckDB 1.5.5 to /home/runner/.duckdb/cli/1.5.5/duckdb. El script leeDUCKDB_VERSIONdel entorno, que el workflow define, así que la versión queda fijada. - CI en Windows: el script no lo admite; el workflow descarga
duckdb_cli-windows-amd64.zipy añade la carpeta aGITHUB_PATH. check.shejecuta cada script conduckdb -csv <y hace un diff contrasql/expected/. Cada sistema operativo tarda uno o dos segundos en todos los scripts de las lecciones 1-4, incluida la consulta HTTPS.
2026-09-14 — Sorpresas al escribir las lecciones 1-4
Sección titulada «2026-09-14 — Sorpresas al escribir las lecciones 1-4»- El
approx_uniquedeSUMMARIZEdaba 131 para 125 identificadores de ejecución únicos, y 17 para 21 nombres de workflow. - La CLI usa la zona horaria del sistema operativo para mostrar
TIMESTAMPTZ(America/…en local, UTC en los runners): el script de la lección 2 defineTimeZoneexplícitamente. sum(INTERVAL)no existe,avg(INTERVAL)sí.labels[0]devuelveNULLsin error.- La flecha de lambda
x -> …imprime un aviso de obsolescencia en 1.5.5; las lecciones usanlambda x: …. - Un job omitido tiene
runner_nameaNULL; el job de despliegue rechazado por la política de ramas del entorno tiene''. - El detector de formato CSV (sniffer) lee en silencio
13/09/2026 15:53comoVARCHAR, y lo mismo pasa con untimestampformatincorrecto. Solo un tipo explícito lo hace fallar. FROM 'data/*.json'fusiona las ejecuciones y los jobs en una sola tabla de 20 columnas, sin ningún aviso.- Primer push del script de la lección 4: falló solo en
macos-latest. Eltotal_compressed_sizede Parquet de 8 bloques de columnas (column chunks) difería de 1 a 6 bytes respecto a Linux y Windows. Ahora el script comparanum_valuesen su lugar. COPYa un archivo existente lo sobrescribe;COPY … PARTITION_BYa una carpeta no vacía falla sinOVERWRITE.
2026-09-14 — Sorpresas al escribir las lecciones 5-6
Sección titulada «2026-09-14 — Sorpresas al escribir las lecciones 5-6»DuckDB.NET.Data.Full1.5.5 ocupa 420 MB en la caché de NuGet, 316 MB enbin/Debugy 69 MB una vez publicado solo paralinux-x64. El jar de JDBC ocupa 85 MB, con cuatro bibliotecas nativas y ninguna build para Windows on Arm.- DuckDB.NET asocia un
STRUCTa una clase por nombre de propiedad, sin distinguir mayúsculas pero sí guiones bajos:StartedAtse queda en silencio con su valor por defecto,Started_Atse rellena. Un record posicional lanzaMissingMethodException. TIMESTAMPTZvuelve como unDateTimeque contiene el valor UTC conKindUnspecified, así queToUniversalTimelo desplaza una segunda vez. En Java es unOffsetDateTimeen la zona horaria por defecto de la JVM, diga lo que digaSET TimeZone.(long)yConvert.ToInt64lanzan una excepción con elBigIntegerde unHUGEINT;(long)(BigInteger)valuefunciona.- Con JDBC, un
Statementse cierra tras una consulta fallida: un bucle que captura el error y sigue hace fallar todas las sentencias siguientes conStatement was closed. - El JDK 25 muestra cuatro advertencias de acceso nativo al cargar el driver, salvo con
--enable-native-access=ALL-UNNAMED; el lanzador de Maven ya lo pasa. - Tiempos en la CI, no comparados: el appender de C# cargó 1.000.000 de filas en 226 a 331 ms y 10.000 sentencias
INSERTsueltas tardaron de 1,3 a 3,9 s; en Java, un batch de JDBC no fue más rápido que las sentencias sueltas (de 690 ms a 2,4 s para 10.000 filas). - Las rutas relativas en el SQL son relativas al directorio de trabajo del proceso, no al proyecto: los dos programas se ejecutan desde
code/duckdb.
2026-09-14 — Sorpresas al escribir las lecciones 7-8
Sección titulada «2026-09-14 — Sorpresas al escribir las lecciones 7-8»- La salida de
EXPLAINno depende del número de hilos, y las estimaciones fueron las mismas en los tres runners, así que la CI puede comparar los planes. - El writer de Parquet usa varios hilos, y el tamaño del mismo archivo de 11 millones de filas cambió entre ejecuciones: 119.021.205 y luego 119.392.814 bytes en local, de 118.714.412 a 119.120.557 bytes en los runners.
- El optimizador reescribe
started_at::DATE = …ydate_trunc('day', started_at) = …como un rango que se salta row groups;strftime(started_at, …) = …sigue siendo una expresión y lee todas las filas: 0,47 s frente a 0,003 s en el archivo ordenado. - Las descargas del Parquet remoto fueron idénticas byte a byte en las cuatro máquinas, y coinciden exactamente con los metadatos: los tres bloques de
trip_distancepara la media, el row group 0 desde el byte 4 paraSELECT * … LIMIT 1. - Una ordenación de 11 millones de filas con
memory_limit = '100MB'falla con 4 hilos y funciona con 1 (de 6,3 a 9,9 s). ElCOPYfallido dejó un archivo parcial. COMMITtras un error dentro de una transacción no muestra ningún error y lo deshace todo, en el CLI y en JDBC. Las cadenas con varias sentencias tampoco son atómicas:-c "a; b; c"ystatement.execute("a; b; c")conservaron las dos primeras filas cuando falló la tercera, aunque la página de transacciones describe una transacción implícita.- Un conflicto de escritura falla en el segundo
UPDATE; una clave duplicada entre dos transacciones, solo en el segundo commit. - Un proceso que tiene abierto un archivo de base de datos bloquea a todos los demás procesos, incluidos los de solo lectura, con un mensaje distinto en cada sistema operativo. Los archivos escritos por DuckDB 1.5.5 llevan la etiqueta
storage_version=v1.0.0+y el CLI de DuckDB 1.0.0 los leyó; conSTORAGE_VERSION 'v1.5.0', la 1.0.0 los rechazó (número de versión 68, solo sabe leer 64). - La CI también ejecuta
timings/07-performance.sql(no comparado: 17 s en Ubuntu, 32 s en Windows, con un archivo CSV de 1 GB) yshell/08-*.sh.
Por verificar
Sección titulada «Por verificar»- Por qué falta el step número 4 en los jobs de
Deploy to GitHub Pages(stepwithastro/action): ¿un step interno de la acción compuesta? - La ruta de instalación de las extensiones en Linux y macOS (
~/.duckdb/extensions/v1.5.5/<platform>/), deducida a partir de la de Windows. - Los comandos de Linux y macOS para ejecutar el programa Java sin Maven (lección 6).
- Los conflictos de escritura y las conexiones de solo lectura con DuckDB.NET (lección 8): probados solo con JDBC.
- Abrir, escribir y cerrar un archivo de base de datos desde varios procesos bajo carga (lección 8, ejercicio 3).
- El protocolo remoto Quack y DuckLake, para varios procesos que escriben: mencionados, no probados.