散列(Hash)

在前面的《字符串》一章中,我们曾经看到过如何使用多个字符串键去储存相关联的一组数据。比如在字符串键实现的文章储存程序中,程序就会为每篇文章创建四个字符串键,并把文章的标题、内容、作者和创建时间分别储存到这四个字符串键里面,图 3-1 就展示了一个使用字符串键储存文章数据的例子。


图 3-1 使用多个字符串键储存文章 _images/IMAGE_ARTICLE_IN_STRINGS.png


使用多个字符串键储存相关联数据虽然在技术上是可行的,但是在实际应用中却并不是最有效的方法,这种储存方法至少存在以下三个问题:

  • 首先,程序每储存一组相关联的数据,就必须在数据库里面同时创建多个字符串键,这样的数据越多,数据库包含的键数量也会越多。数量庞大的键会对数据库某些操作的执行速度产生影响,并且维护这些键也会产生大量的资源消耗。

  • 其次,为了在数据库里面标识出相关联的字符串键,程序需要为它们加上相同的前缀,但键名实际上也是一种数据,储存键名也需要耗费内存空间,因此重复出现的键名前缀实际上导致很多内存空间被白白浪费了。此外,带前缀的键名还降低了键名的可读性,让人无法一眼看清键的真正用途,比如键名 article::10086::author 就远不如键名 author 简洁,而键名 article::10086::title 也远不如键名 title 来得简洁。

  • 最后,虽然程序在逻辑上会把带有相同前缀的字符串键看作是相关联的一组数据,但是在 Redis 看来,它们只不过是储存在同一个数据库中的不同字符串键而已。因此当程序需要处理一组相关联的数据时,它就必须对所有有关的字符串键都执行相同的操作。比如说,如果程序想要删除 ID 为 10086 的文章,那么它就必须把 article::10086::titlearticle::10086::content 等四个字符串键都删掉才行,这给文章的删除操作带来了额外的麻烦,并且还可能会因为漏删或者错删了某个键而发生错误。

为了解决以上问题,我们需要一种能够真正地把相关联的数据打包起来储存的数据结构,而这种数据结构就是本章要介绍的散列键。