Thursday, October 03, 2013

SAP HANA - Hablemos de Filas y Columnas

Como ya sabemos todos...SAP HANA puede manejar la creacion de tablas de dos maneras...Filas y Columnas. Las tablas de Filas se supone que son mejores para tablas que se actualizan constantemente y las tablas de Columnas son para tablas que no se actualizan constantemente...las tablas de Columnas se supone que son mucho mas rapidas cuando se trata de leer informacion.

Como nunca he hecho una prueba de esto...cree dos scripts en Python para generar 1 millon de registros para dos tablas...DOC_HEADER y DOC_DETAILS. Estas dos tablas comparten los campos DOCUMENT_ID, YEAR y AREA pero como la informacion es creada de forma aleatoria, la posibilidad de que ambas tablas compartan la misma informacion es desconocida...

Para propositos de este ejemplo cree ambas tablas DOC_HEADER y DOC_DETAILS utilizando los dos tipos Filas y Columnas y cree otros script en Python para medir el tiempo de lectura...

Column_Row_SAPHANA_Test.py
import dbapi
import time

conn = dbapi.connect('*****', 30015, 'SYSTEM', '****')
cur = conn.cursor()

query = '''SELECT H."DOCUMENT_ID", H."YEAR", H."AREA", SUM("AMOUNT") AS AMOUNT
           FROM "BLAG"."DOC_HEADER_ROW" AS H INNER JOIN "BLAG"."DOC_DETAIL_ROW" AS D
           ON H."DOCUMENT_ID" = D."DOCUMENT_ID"
           AND H."YEAR" = D."YEAR"
           AND H."AREA" = D."AREA"
           GROUP BY H."DOCUMENT_ID", H."YEAR", H."AREA"'''

start = time.clock()
cur.execute(query)
ret = cur.fetchall()
end = time.clock()

counter = 0

for row in ret:
    counter += 1
time_taken = end - start
print("Row Store - %s records in %s seconds") %(counter, time_taken)

query = '''SELECT H."DOCUMENT_ID", H."YEAR", H."AREA", SUM("AMOUNT") AS AMOUNT
           FROM "BLAG"."DOC_HEADER_COLUMN" AS H INNER JOIN "BLAG"."DOC_DETAIL_COLUMN" AS D
           ON H."DOCUMENT_ID" = D."DOCUMENT_ID"
           AND H."YEAR" = D."YEAR"
           AND H."AREA" = D."AREA"
           GROUP BY H."DOCUMENT_ID", H."YEAR", H."AREA"'''

start = time.clock()
cur.execute(query)
ret = cur.fetchall()
end = time.clock()

counter = 0

for row in ret:
    counter += 1
time_taken = end - start
print("Column Store - %s records in %s seconds") %(counter, time_taken)

Las dos consultas hacen exactamente lo mismo...hacen un INNER JOIN entre las dos tablas...utilizando almacenamiento en Filas para el primero y almacenamiento en Columnas para la segunda...

Ejecutamos estos 3 veces y veamos que pasa -;)

Benchmark
Row Store - 7669 records in 2.45972177882 seconds
Column Store - 7669 records in 1.59409638594 seconds

Row Store - 7669 records in 2.32650395252 seconds
Column Store - 7669 records in 1.68382533783 seconds

Row Store - 7669 records in 2.44930342075 seconds
Column Store - 7669 records in 1.52396673192 seconds

Como podemos ver...tenemos una ganancia constante de aproximadamente 38% mas de velocidad cuando utilizamos almacenamiento en Columnas...

Saludos,

Blag.
Developer Experience.

No comments: