¿Dónde encuentro el capítulo que me interesa de un libro? ¿A dónde se dirige el pedido de Ana García? ¿Dónde puedo comprar ese reloj con la correa de cuero marrón? Lo que estas frases tienen en común, además de que son preguntas, es que preguntan por un lugar: ¿dónde? ¿adónde? Otro punto en común es que las tres suponen que el objeto buscado existe. Esta es­tru­c­tu­ra de pe­n­sa­mie­n­to puede usarse fá­ci­l­me­n­te como ejemplo de lo que sucede en una base de datos.

Imagina una tienda online con miles de artículos y de clientes. Los datos de todos ellos se almacenan en bases de datos: el cliente busca en una base de datos un artículo concreto y hace su pedido; el expedidor usa una base de datos para asignar el artículo al comprador y a su dirección postal. Este proceso conlleva tareas de cla­si­fi­ca­ción, adición y eli­mi­na­ción mientras se realiza el pedido. Para poder ge­s­tio­nar­las de forma más eficiente, se resumen grandes ca­n­ti­da­des de datos con elementos en común en una posición de dirección en la base de datos. Dicha posición se calcula con valores hash y está compuesta por una tabla con co­m­bi­na­cio­nes de cifras y letras, todas de la misma longitud. En este artículo te ex­pli­ca­mos los conceptos básicos para que puedas usar tablas hash (hash tables).

¿Qué principio sigue una tabla hash?

A partir de los datos de un registro se calcula, en primer lugar, un valor hash. Los valores hash de todos los registros de una base de datos se guardan en la tabla hash. Mediante otra operación ma­te­má­ti­ca, a partir del valor hash se calcula la ubicación de dicha in­fo­r­ma­ción en la base de datos. Si el usuario introduce entonces un término en el campo de búsqueda, este término también se hashea. A partir de entonces, por lo tanto, ya no se busca “reloj con la correa de cuero marrón”, sino una coin­ci­de­n­cia entre el valor hasheado ini­cia­l­me­n­te para el artículo y el valor hash del término buscado en ese momento. En otras palabras, se busca una coin­ci­de­n­cia entre dos co­m­bi­na­cio­nes de cifras y letras. Este enfoque se usa para todo tipo de apli­ca­cio­nes.

Seguridad con valores hash

Una tabla hash es el resultado de asignar hashes generados au­to­má­ti­ca­me­n­te a ciertos términos de búsqueda. Para ello se usa una función hash, que genera una secuencia de ca­ra­c­te­res con una longitud constante llamada hash. La longitud de la secuencia y los ca­ra­c­te­res que la forman son es­ta­ble­ci­dos por el método hash que se esté uti­li­za­n­do. Este método se usa, por ejemplo, para proteger datos de acceso frente al robo de datos.

En los inicios de sesión re­gi­s­tra­dos en la base de datos de la imagen, la co­n­tra­se­ña in­tro­du­ci­da por el usuario se convierte a un valor hash mediante el mismo pro­ce­di­mie­n­to. Este valor se coteja entonces con la entrada que le co­rre­s­po­n­de en el campo user_pass de la base de datos. Si ambos hashes de 34 ca­ra­c­te­res coinciden, se concede el acceso. En sentido opuesto, no es posible descifrar una co­n­tra­se­ña a partir de un valor hash: esta es una de las cua­li­da­des de las funciones hash.

Si el intento de acceso no au­to­ri­za­do, en cambio, se basa en un ataque de fuerza bruta, la secuencia debe probarse usando todos los ca­ra­c­te­res pe­r­mi­ti­dos hasta dar con una coin­ci­de­n­cia exacta. Si se incluyen mi­nú­s­cu­las, ma­yú­s­cu­las y números, y su­po­nie­n­do que el atacante conozca la función hash utilizada, una co­n­tra­se­ña de 10 ca­ra­c­te­res re­que­ri­ría exac­ta­me­n­te 839.299.365.868.340.200 intentos para dar a ciencia cierta con la co­m­bi­na­ción correcta.

Acelerar los procesos de las bases de datos

En las bases de datos se utilizan tablas hash para acelerar los procesos de búsqueda, de registro y de eli­mi­na­ción de conjuntos de datos. Ima­gi­ne­mos que se busca un apellido en una base de datos que incluya a todos los tra­ba­ja­do­res de una empresa: la tarea puede llevar mucho tiempo porque, de manera co­n­ve­n­cio­nal, se busca la coin­ci­de­n­cia en cada uno de los campos de la base de datos, uno tras otro (de manera se­cue­n­cial). Si, en cambio, se convierte el término de búsqueda en un valor hash para luego buscarlo en la tabla hash, el proceso suele llevar mucho menos tiempo.

¿Cómo se hace esto exac­ta­me­n­te? A cada conjunto de datos se le asigna una dirección ine­quí­vo­ca. Las reglas que rigen esta asi­g­na­ción son siempre las mismas dentro de cada base de datos (001, 002, 003 o 00A1, 00A2, 00A3, etc.). La dirección se calcula con ayuda de la función hash.

Como ejemplo sencillo, pongamos que tenemos una base de datos con espacio para 11 entradas, en las po­si­cio­nes de 0 a 10. El nombre Lisa está formado por 4 ca­ra­c­te­res ASCII, cada uno con un código ASCII: L es 76, i es 105, s es 115 y a es 97. Puedes comprobar esta asi­g­na­ción tú mismo usando el teclado numérico: verás que con [Alt] + 0076, por ejemplo, se muestra una L. Se suman entonces todos los valores ASCII de Lisa, dando como resultado el valor hash 393. En este caso, la suma de los valores ASCII co­rre­s­po­n­de a una función hash.

A co­n­ti­nua­ción, se realiza un cálculo del residuo con números enteros: 393 % 11 (entradas que caben en la base) = 35, residuo 8 (en muchos lenguajes de pro­gra­ma­ción el símbolo de po­r­ce­n­ta­je % co­rre­s­po­n­de al operador ma­te­má­ti­co del cálculo del residuo). Este residuo será el que determine en qué lugar de la base de datos (en nuestro cálculo de ejemplo, el índice número 8) se guardará Lisa y todos los datos re­la­cio­na­dos con ella. Como ya habrás imaginado, en este tipo de di­re­c­cio­na­mie­n­to, los residuos re­su­l­ta­n­tes a menudo se repiten. Cuanto más espacio de al­ma­ce­na­mie­n­to y más largo sea el valor hash utilizado, menor será la pro­ba­bi­li­dad de que ocurran tales re­pe­ti­cio­nes. En el caso del nombre Alis, aunque las letras del nombre coincidan con las de Lisa, el po­si­cio­na­mie­n­to sería diferente, ya que la A es mayúscula y la L es minúscula.

En la imagen anterior podemos ver un problema de re­pe­ti­ción: es posible que nombres distintos reciban los mismos valores de índice, causando así las llamadas co­li­sio­nes (flechas azul claro). ¿Cómo reacciona la base de datos ante este obstáculo? Ubica el registro en la posición libre más cercana. Así, si se busca Berta Torres, por ejemplo, la búsqueda no comenzará en la posición 001, sino que el puntero de búsqueda irá di­re­c­ta­me­n­te a la posición de índice 003, lo cual supone una (ligera) ace­le­ra­ción del proceso. Este método, en el que luego se busca de forma lineal, se conoce como hashing con di­re­c­cio­na­mie­n­to abierto (o sondeo lineal).

Por su parte, el método del hashing en­ca­de­na­do (chaining) funciona de manera diferente: no se abre ningún conjunto de datos nuevo, sino que se va en­ca­de­na­n­do el primer conjunto de datos coin­ci­de­n­te con el siguiente. De esta manera, el conjunto de datos buscado se localiza con una sola solicitud de búsqueda, ya que está lo­ca­li­za­do tras el primer conjunto en la posición de la memoria. Como co­n­se­cue­n­cia, el pro­ce­sa­mie­n­to se vuelve más rápido.

Al buscar Berta Torres, el puntero de datos se coloca así desde el principio sobre el valor 003, calculado a partir de la tabla hash, y a partir de entonces ya solo le queda examinar un conjunto en­ca­de­na­do de datos. De esta forma pueden agruparse y exa­mi­nar­se grandes ca­n­ti­da­des de datos de forma más rápida y so­fi­s­ti­ca­da.

El método conocido como caching también utiliza este principio para recuperar datos que hayan sido usados alguna vez. Estos datos se guardan en la memoria temporal o memoria caché, desde donde se recuperan en caso de coin­ci­de­n­cia con un patrón de actividad. Esto se aplica, por ejemplo, a páginas webs que han sido visitadas, de manera que en una segunda visita ya no se tienen que cargar co­m­ple­ta­me­n­te desde el servidor, sino que se recuperan, de forma mucho más rápida, de la memoria caché. Las cookies también funcionan como una especie de ide­n­ti­fi­ca­ción por co­m­pa­ra­ción que indica qué lugares de la web ha visitado el usuario.

¿Qué variantes del proceso hash existen?

El proceso de hashing que hemos descrito en este artículo se denomina también hashing abierto o externo, ya que en él pueden al­ma­ce­nar­se datos en forma de listas en­ca­de­na­das dentro de un espacio infinito, al menos en teoría. Si bien las claves sí son limitadas, el en­ca­de­na­mie­n­to permite procesar mayores ca­n­ti­da­des de datos. La ca­li­fi­ca­ción de abierto hace re­fe­re­n­cia al di­re­c­cio­na­mie­n­to.

En el caso del hashing cerrado, en cambio, el número de claves está limitado por la capacidad de la tabla. Si se intentan guardar más datos, se produce un llamado overflow o de­s­bo­r­da­mie­n­to. Con cada nueva exa­mi­na­ción, la tabla se sondea para buscar po­si­cio­nes libres en las que poder ubicar los elementos de­s­bo­r­da­dos.

Nota

No hay reglas claras que definan el si­g­ni­fi­ca­do de los términos abierto y cerrado para calificar los procesos de hashing. En algunas pu­bli­ca­cio­nes se utilizan incluso de forma opuesta a la que de­s­cri­bi­mos aquí. Es re­co­me­n­da­ble, por lo tanto, tomar como re­fe­re­n­cia una de­s­cri­p­ción detallada de cada concepto.

Por otro lado, el llamado hash del cuco o cuckoo hashing también se aplica para evitar co­li­sio­nes en la tabla de la base de datos. Este método debe su nombre al co­m­po­r­ta­mie­n­to del cuco, que quita los huevos de nidos ajenos para colocar en ellos los propios. De forma similar, el hash del cuco aplica dos funciones hash para definir dos po­si­cio­nes de al­ma­ce­na­mie­n­to. Si la primera posición ya está ocupada, la clave allí ubicada será tra­s­la­da­da a otra posición, de forma que la segunda clave generada pueda colocarse en la primera posición. El in­co­n­ve­nie­n­te de esta variante es que puede generar un bucle inaca­ba­ble de búsqueda, de forma que una rutina iniciada se in­te­rru­m­pi­ría porque superaría el tiempo asignado.

En lo que respecta al sondeo de la base de datos, existen di­fe­re­n­tes métodos co­n­s­trui­dos a base de complejas fórmulas ma­te­má­ti­cas y que se ocultan en forma de código de programa en una página web, por ejemplo, tras la barra de búsqueda con el icono de la lupa.

Por lo general, las bases de datos se vuelven cada vez más complejas; la cantidad de datos que co­m­pre­n­den aumenta cada vez más rápido. Por este motivo, el hashing dinámico aumenta la tabla hash para evitar co­li­sio­nes. Esto, sin embargo, hace que se mo­di­fi­quen también los valores hash de los datos ya al­ma­ce­na­dos. Para so­lu­cio­nar este problema de forma eficiente, se han de­sa­rro­lla­do funciones hash es­pe­cia­les. Con ello, la capacidad de al­ma­ce­na­mie­n­to de datos pasa a ser, al menos en teoría, ilimitada, si bien los ciclos de búsqueda se vuelven menos efi­cie­n­tes.

Ventajas e in­co­n­ve­nie­n­tes de las tablas hash

La mayor ventaja que ofrece el uso de una tabla hash es la velocidad de búsqueda en grandes conjuntos de datos. Para lograrlo, sin embargo, los ar­qui­te­c­tos de la base de datos se enfrentan al desafío de estimar por ade­la­n­ta­do el tamaño necesario, con el fin de reducir el riesgo de co­li­sio­nes. Pueden usarse muchos tipos de datos di­fe­re­n­tes, siempre y cuando puedan ca­l­cu­lar­se valores hash a partir de ellos.

En cuanto a los puntos débiles de este método, uno de ellos es la posible de­ge­ne­ra­ción grave del sistema si se producen muchas co­li­sio­nes. La pro­ba­bi­li­dad de las co­li­sio­nes aumenta a medida que lo hace la cantidad de datos al­ma­ce­na­dos. La presencia de una gran cantidad de funciones hash impide mo­vi­mie­n­tos de un conjunto de datos al anterior o al siguiente.

Ir al menú principal