Sin duda es el talón de aquiles de Magento, y la base de muchos de los problemas que impiden que explote como la plataforma de comercio electrónico definitiva: el modelo de base de datos EAV y su rendimiento.
De todos es conocido a estas alturas que Magento es una plataforma que devora los recursos de cualquier servidor. Incluso en servidores virtuales sin una configuración adecuada, la carga de las páginas puede eternizarse y el uso del panel de gestión ser una pesadilla.
Una gran parte de estos problemas de rendimiento es el mencionado modelo EAV (Entity Value Attribute).
En los siguientes párrafos intentaré explicar las diferencias entre el modelo de base de datos relacional (típico en otras plataformas de comercio electrónico) y el modelo de base de datos EAV adoptado por Magento.
Para ello, intentaremos extraer de la base de datos de dos plataformas (Magento y Prestashop), el nombre de un cliente y su dirección postal a partir de su identificador de cliente en la base de datos.
El objetivo no es extraer el nombre mediante las funciones del API de cada una de las plataformas, sino analizar la estructura de la base de datos para saber el trabajo que deben realizar esas funciones y así poder explicar la diferencia de rendimiento.
El modelo de datos tradicional: modelo relacional
Para extraer de la base de datos el nombre de un cliente en Prestashop, sólo debemos ir a la tabla ps_customer, que presenta la siguiente estructura:
A partir del identificador de cliente, sólo es necesario realizar una consulta simple como:
SELECT firstname, lastname FROM ps_customer WHERE id_customer = '1'
Si queremos extraer también la dirección, debemos acudir también a la tabla ps_address, donde se encuentran almacenadas todas las direcciones.
SELECT c.firstname, c.lastname, a.* FROM ps_customer c, ps_address a WHERE c.id_customer = a.id_customer AND c.id_customer = '1'
Sencillo, ¿no?. Lo es porque en el modelo relacional cada tabla representa la información necesaria de un objeto, modelo o entidad (como prefieras llamarlo). Así, la tabla ps_customer define los datos básicos de un cliente y la tabla ps_address define los datos de una dirección.
Para indicar que una dirección pertenece a un cliente, en ambas tablas aparece un identificador común (el identificador del cliente), que las relaciona.
El modelo de base de datos de Magento: modelo EAV
El modelo EAV es en general mucho más flexible, ya que por ejemplo, el número y tipo de campos que definen un cliente no está fijado a priori, como en el caso relacional, donde dichos campos vienen establecidos por las ‘columnas’ de la tabla.
En el modelo EAV, los campos que definen cada entidad (en este caso a un cliente) también están almacenados en la propia base de datos.
Lo primero que debemos hacer en el modelo EAV es identificar donde se almacena la definición de un cliente. Para ello, en Magento deberemos recurrir a la tabla eav_entity_type y comprobar lo siguiente:
Obtenemos un identificador de la definición de cliente (entity_type_id:1) y una tabla donde se guarda su información (customer/entity).
Vayamos entonces a la tabla customer_entity y veamos su estructura:
No, parece que de aquí no vamos a obtener el nombre del cliente… ¿que está pasando?. Si nos fijamos, la tabla customer_entity, tiene otras tablas similares cerca, en este caso:
- customer_entity
- customer_entity_datetime
- customer_entity_decimal
- customer_entity_int
- customer_entity_text
- customer_entity_varchar
Ninguna de ellas parece que pueda ayudarnos a obtener el nombre del cliente tampoco, o al menos sus nombres no parecen indicar mucho.
Como hemos dicho, el modelo EAV guarda la definición de las entidades en la propia base de datos. Al consultar directamente la tabla customer_entity, nos hemos saltado un paso, que es saber en que tabla se encuentra el nombre del usuario (si es que existe, que todavía no lo sabemos).
Para saber en que tabla mirar, debemos acudir a otras dos tablas de información global de Magento: eav_entity_attribute y eav_attribute. Para no alargar mucho el tema nos saltaremos la primera de ellas, y viendo directamente la segunda, veremos algo como lo siguiente.
Vemos una serie de registros que tienen entity_type_id = 1 (hace un rato vimos que este identificador corresponde a la definición de cliente). En concreto: nombre, apellido, email, password, envío y facturación. Parece, efectivamente, que esos datos pueden formar parte de lo que define a un cliente (y efectivamente lo es).
Si nos fijamos en el registro ‘firstname’, vemos que además existen otros dos datos relevantes:
attribute_id = 1 backend_type = varchar
Mas arriba en este mismo artículo, listábamos las tablas relacionadas con los datos de los clientes. Casualmente vemos una tabla denominada customer_entity_varchar… sospechoso…
Vayamos a esa tabla y comprobemos su contenido.
Bingo! Parece el nombre del cliente. Si vemos las columnas marcadas, vemos que entity_type_id corresponde con el tipo de entidad que buscamos (cliente), attribute_id corresponde con el atributo que buscamos (nombre) y entity_id es el identificador único del cliente (similar a la columna id_customer en el ejemplo de Prestashop).
Resumiendo, hemos tenido que buscar en 4 tabla para extraer el nombre del cliente.
SELECT a.entity_type_id, a.attribute_id, et.entity_type_code, a.attribute_code, a.backend_type FROM eav_entity_type et, eav_attribute a, eav_entity_attribute ea WHERE et.entity_type_code = 'customer' AND a.attribute_code = 'firstname' AND et.entity_type_id = ea.entity_type_id AND et.entity_type_id = a.entity_type_id AND ea.attribute_id = a.attribute_id
Y con esto obtenemos algo de información útil
Pero no el nombre del cliente. Para ello necesitaremos realizar otra nueva consulta, basada en los datos retornados por la primera.
SELECT value FROM customer_entity_varchar WHERE entity_type_id = '1' AND attribute_id = '1' AND entity_id = '2'
Podríamos seguir profundizando, pero creo que hasta aquí es suficiente para valorar la diferencia en la complejidad de una y otra bases de datos.
¿Por qué EAV?
No pretendo establecer una crítica general al modelo EAV. El modelo es útil en determinadas circunstancias, pero tal vez esas circunstancias no correspondan con las necesidades de Magento.
El modelo EAV es útil cuando los atributos que definen a una entidad pueden ser muy variados, pero no se conocen todos los atributos de todas las entidades. Por ejemplo imaginemos que queremos definir a personas: deberíamos ser capaces de almacenar información como datos personales (nombre, apellidos, origen, fecha de nacimiento, etc), datos de contacto (dirección, teléfono, email, etc.), datos físicos (altura, peso, color de pelo, talla de zapatos, etc.), orientación política y religiosa, propiedades, datos financieros, laborales, etc.
Toda esa información debería tener cabida en la base de datos, pero no siempre podremos definir todas las características de cada persona.
En este caso el modelo EAV presenta la ventaja de la optimización de espacio, frente al modelo relacional.
Pero este no es el caso de Magento.
Conclusiones
Como hemos visto, el modelo EAV de la base de datos de Magento requiere del uso de hasta 4 tablas para obtener datos que en otros modelos se obtienen de forma directa. Además, las consultas son más complejas y se requiere del uso de resultados intermedios que ralentizan todavía más el proceso.
Por todo ello, y viendo el tipo de datos que se almacenan en una tienda online, el modelo EAV no es el adecuado para una plataforma como Magento, y de ello ya se han percatado los diseñadores de la misma, ya que desde hace un par de versiones, están creando un segundo modelo de datos (en paralelo) que a futuro dejará obsoleto el modelo EAV.
¡Parece que estés describiendo el modelo de datos del ITS de esa empresa que tu y yo conococemos! (Con todos sus problemas)
Ya te digo… ya lo decían mis profesores del ‘cole’…. antes de liarte a escribir código, mejor coge un papel y hazte cuatro diagramas, que si no, no harás mas que poner parches el resto del proyecto…
Me seria util ver otra propuesta que no sea de Magento, esto es debido a lo escrito por con aterioridad » … En este caso el modelo EAV presenta la ventaja de la optimización de espacio, frente al modelo relacional. Pero este no es el caso de Magento….», y que me ha dejado con esa inquietud, estoy tratando de desarrollar una BD EAV, pero diferente al contexto Magento. Saludos
Estimado Daniel:
Mi nombre es Pablo Lires, resido en Argentina y hace no mucho comencé a utilizar Magento.
Ante todo felicitaciones por tu sitio, realmente entendi muchísimas cosas de Magento gracias a tu clara explicación.
En esta ocasión estoy necesitando agregar dos atributos en el checkout (fecha y hora de entrega del producto), realmente hace mucho que estoy leyendo artículos y tutoriales pero lamentablemente no puedo avanzar.
Si fueras tan gentil y si conoces algún tutorial para lograr realizar esta tarea te lo agradeceria muchísimo.
Muchas gracias por tu tiempo y felicitaciones nuevamente por la calidad y profesionalismo de tu sitio.
Estimado Daniel, soy nuevo en Magento, aunque llego 20 años trabajando con bases de datos, sobre tod MS SQL, tu aportación me ha ayudado rapidamente a tener una idea clara del modelo.
Agradezco mucho la misma y si algún día puedo devolverte el favor lo mio es MS SQL .Net