Artículo
· 29 feb, 2024 Lectura de 5 min

Poniendo a prueba el Columnar Storage

Como seguramente ya sabréis la mayoría de vosotros, desde aproximadamente finales de 2022 InterSystems IRIS incluyo la funcionalidad de almacenamiento columnar a su base de datos, pues bien, en el artículo de hoy vamos a ponerla a prueba en comparación con el almacenamiento en filas habitual.

Almacenamiento columnar

¿Cuál es la principal característica de este tipo de almacenamiento? Pues bien, si consultamos la documentación oficial veremos esta fantástica tabla que nos explica las principales características de ambos tipos de almacenamiento (por filas o por columnas):

Como véis el almacenamiento columnar está pensado sobretodo para tareas de tipo analítico en las que se lanzan consultas contra campos específicos de nuestra tabla, mientras que el almacenamiento por filas es más óptimo cuando se requiere realizar gran número de operaciones de inserción, actualización y eliminación, así como obtener registros íntegros.

Si seguís leyendo la documentación veréis lo sencillo que es configurar nuestra tabla para poder utilizar el almacenamiento columnar:

CREATE TABLE table (column type, column2 type2, column3 type3) WITH STORAGETYPE = COLUMNAR

Mediante este comando estaríamos definiendo todas las columnas de nuestra tabla con almacenamiento columnar, pero podríamos decantarnos por un modelo mixto en el que nuestra tabla tenga un almacenamiento en filas pero que determinadas columnas hagan uso del almacenamiento columnar.

Este escenario mixto podría ser interesante en casos en los que sean habitual operaciones de agregación como sumas, medias, etc. Para este caso podríamos definir que columna es la que hará uso de dicho almacenamiento:

CREATE TABLE table (column type, column2 type2, column3 type3 WITH STORAGETYPE = COLUMNAR)

En el ejemplo anterior definiríamos una tabla con almacenamiento por filas y una columna (column3) con almacenamiento columnar.

Comparativa

Para realizar la comparativa entre el tiempo empleado por almacenamiento columnar y el de por filas en diferentes consultas hemos creado un pequeño ejercicio haciendo uso de Jupyter Notebook que va a insertar una serie de registros que generaremos en dos tablas, la primera con almacenamiento con filas (Test.PurchaseOrderRow) y la segunda con almacenamiento columnar en dos de sus columnas (Test.PurchaseOrderColumnar)

Test.PurchaseOrderRow

CREATE TABLE Test.PurchaseOrderRow (
    Reference INTEGER,
    Customer VARCHAR(225),
    PaymentDate DATE,
    Vat NUMERIC(10,2),
    Amount NUMERIC(10,2),
    Status VARCHAR(10))

Test.PurchaseOrderColumnar

CREATE TABLE Test.PurchaseOrderColumnar (
    Reference INTEGER,
    Customer VARCHAR(225),
    PaymentDate DATE,
    Vat NUMERIC(10,2),
    Amount NUMERIC(10,2) WITH STORAGETYPE = COLUMNAR,
    Status VARCHAR(10) WITH STORAGETYPE = COLUMNAR)

Si os descargais el proyecto de Open Exchange y lo desplegáis en vuestro Docker local podréis acceder a la instancia de Jupyter Notebook y revisar el archivo PerformanceTests.ipynb el cual será el encargado de generar los datos aleatorios que vamos a almacenar en diferentes fases en nuestras tablas y finalmente nos mostrará una gráfica con el rendimiendo de las operaciones de consulta.

Echemos un vistazo rápido a la configuración de nuestro proyecto:

docker-compose.yml

version: '3.7'
services:
  # iris
  iris:
    init: true
    container_name: iris
    build:
      context: .
      dockerfile: iris/Dockerfile
    ports:
      - 52774:52773
      - 51774:1972
    volumes:
    - ./shared:/shared
    environment:
    - ISC_DATA_DIRECTORY=/shared/durable
    command: --check-caps false --ISCAgent false
  # jupyter notebook
  jupyter:
    build:
      context: .
      dockerfile: jupyter/Dockerfile
    container_name: jupyter
    ports:
      - "8888:8888"
    environment:
      - JUPYTER_ENABLE_LAB=yes
      - JUPYTER_ALLOW_INSECURE_WRITES=true
    volumes:
      - ./jupyter:/home/jovyan
      - ./data:/app/data
    command: "start-notebook.sh --NotebookApp.token='' --NotebookApp.password=''" 

Desplegamos en nuestro docker los contenedores de IRIS y Jupyter, configurando al inicio IRIS con el namespace "TEST" y las dos tablas requeridas para la prueba.

Para no aburriros con código podéis consultar vosotros mismos el archivo PerformanceTests.ipynb desde el que nos conectaremos a IRIS, generaremos los registros a insertar y los almacenaremos en IRIS

Ejecución de las pruebas

Los resultados han sido los siguientes (en segundos):

Inserciones:

Las inserciones realizadas son de tipo bulk:

INSERT INTO Test.PurchaseOrderColumnar (Reference, Customer, PaymentDate, Vat, Amount, Status) VALUES (?, ?, ?, ?, ?, ?)

Y el tiempo para cada lote de inserciones es el siguiente:

Total de inserciones

Almacenamiento por filas Almacenamiento mixto
1000

0.031733

0.041677

5000

0.159338

0.185252

20000

0.565775

0.642662

50000

1.486459

1.747124

100000

2.735016

3.265492

200000

5.395032

6.382278

Consultas:

La consulta lanzada incluye una función de agregación y una condición, ambas sobre las columnas con almacenamiento columnar: 

SELECT AVG(Amount) FROM Test.PurchaseOrderColumnar WHERE Status = 'SENT'

Total de filas

Almacenamiento por filas Almacenamiento mixto
1000

0.002039

0.001178

5000

0.00328

0.000647

20000

0.005493

0.001555

50000

0.016616

0.000987

100000

0.036112

0.001605

200000

0.070909

0.002738

Conclusiones

Como veis en los resultados obtenidos, el funcionamiento es exactamente a lo que se indica en la documentación. La inclusión de columnas con almacenamiento columnar ha penalizado levemente el rendimiento durante la inserción (un 18% más lento aproximadamente para nuestro ejemplo) mientras que las consultas sobre esas mismas columnas han mejorado espectacularmente el tiempo de respuesta (258 veces más rápida).

Sin duda es algo a tener en cuenta en el momento de planificar el desarrollo de cualquier aplicación.

Comentarios (2)1
Inicie sesión o regístrese para continuar