7 puntos por GN⁺ 2024-05-01 | 1 comentarios | Compartir por WhatsApp

Cómo funcionan normalmente los motores de bases de datos SQL

  • Todos los motores de bases de datos SQL funcionan de manera similar
    • Convierten la sentencia SQL de entrada en una "sentencia preparada" (Prepared Statement)
    • Ejecutan la sentencia preparada para producir resultados
  • En SQLite, una sentencia preparada se representa como una instancia del objeto sqlite3_stmt
  • Hay dos formas principales de representar una sentencia preparada
    • Método de bytecode: usado en SQLite
    • Método de árbol de objetos: usado en MySQL y PostgreSQL

Ventajas del método de bytecode

  • Es fácil de entender
    • Está compuesto por una secuencia de instrucciones simples, por lo que se puede imprimir fácilmente
    • Si se usa la palabra clave EXPLAIN, es posible ver el bytecode de la sentencia SQL
  • Facilita la depuración
    • Distingue claramente entre la etapa de parsing/análisis y la etapa de ejecución
    • En compilaciones de depuración, se puede rastrear la ejecución del bytecode con el comando PRAGMA vdbe_trace=ON
  • Permite ejecución incremental
    • Una sentencia SQL escrita en bytecode puede ejecutarse fila por fila, detenerse y reanudarse
    • En el método de árbol de objetos, se ejecuta todo el árbol de una sola vez, por lo que la ejecución incremental es difícil
  • Usa menos memoria
    • El bytecode ocupa menos espacio que el AST
    • Como las Prepared Statement suelen mantenerse en caché en memoria durante mucho tiempo, el uso de memoria es importante
  • La velocidad de ejecución es alta
    • Hay menos decisiones que tomar en cada etapa, por lo que la ejecución es más rápida

Ventajas del método de árbol de objetos

  • Permite modificar el plan de consulta en tiempo de ejecución
    • Un árbol de objetos se puede modificar fácilmente incluso durante la ejecución
    • Es posible optimizar dinámicamente según el progreso de la consulta
  • Es fácil de paralelizar
    • Cada nodo de procesamiento puede asignarse a un hilo separado
    • Solo hace falta sincronizar la transferencia de datos entre nodos
    • Es ventajoso al ejecutar consultas analíticas de gran volumen (OLAP) en múltiples núcleos

Opinión de GN⁺

  • Como el objetivo principal de SQLite es el procesamiento transaccional (OLTP) en entornos de internet de las cosas, el método de bytecode parece adecuado. Esto se debe a que puede ofrecer un rendimiento rápido siendo simple y ligero.
  • En cambio, como MySQL y PostgreSQL también se usan mucho para análisis de grandes volúmenes de datos, pueden destacarse más las ventajas del método de árbol de objetos, que permite optimizar dinámicamente la ejecución de consultas y paralelizarla.
  • Aun así, el método de árbol de objetos también tiene desventajas, como que la depuración o el análisis de rendimiento resultan más difíciles. Además, debido al costo de recorrer el árbol y otros factores, en consultas simples incluso podría ser más lento que el bytecode.
  • Lo importante es elegir el enfoque adecuado según el uso y el objetivo. En el caso de un RDBMS de propósito general, también valdría la pena considerar un enfoque híbrido que combine las ventajas y desventajas de ambos métodos.

1 comentarios

 
GN⁺ 2024-05-01
Opinión de Hacker News
  • Que SQLite use una máquina virtual (VM) de bytecode en lugar de un árbol de sintaxis abstracta (AST) para ejecutar consultas SQL es una decisión de diseño interesante para una base de datos. Las ventajas del bytecode frente al AST son las siguientes:

    • Compacidad: el bytecode es más compacto que un AST porque no necesita malloc ocultos, encabezados de objetos ni punteros para las subexpresiones.
    • Rendimiento: la ejecución de bytecode es más rápida por su mejor uso de caché y por tener menos fallos de caché causados por el seguimiento de punteros.
    • Ejecución incremental: con una pila explícita, es más fácil pausar y reanudar la ejecución con bytecode sin desenrollar la pila principal.
  • Las VM de bytecode y los intérpretes suelen asociarse con lenguajes de programación de propósito general, pero también pueden ser sorprendentemente útiles en otros contextos, como los siguientes:

    • eBPF: mecanismo de extensión del kernel de Linux.
    • Lenguaje de expresiones DWARF: usado por depuradores como GDB y LLDB.
    • Formato de archivo RAR: incluye codificación en bytecode para transformaciones de datos personalizadas.
  • Microsoft SQL Server usa internamente árboles de objetos, pero la salida del plan de consultas sigue presentándose en forma de tablas, lo que muestra la dificultad de renderizar un árbol de objetos como tabla.

  • Los programadores a menudo saben exactamente qué búsquedas de índice deben ocurrir dentro de un bucle, así que en algunos casos puede ser ventajoso escribir bytecode directamente o usar un lenguaje imperativo de alto nivel en lugar de SQL. Expresarlo en SQL puede ser una carga.

  • Si el cuello de botella no está en la ejecución del bytecode (por ejemplo, en la velocidad de memoria o de disco), quizá no sea necesario convertirlo a código nativo mediante compilación JIT.

  • Muchos lenguajes de programación, como Python, Ruby y Lua, usan internamente bytecode o AST. Debido a decisiones de diseño de bases de datos, puede ser útil contar con instrucciones fáciles de analizar para bibliotecas de terceros o implementaciones de ORM propensas a errores.