你可以将顶点表示为表,将边也表示为表。那么,图到底有什么不同,为什么我们声称它对于多跳操作更快?首先,图不仅仅是用于可视化的。尽管我们可视化数据是为了方便自己,但计算机根本不需要这种可视化。
图的性能优势体现在关系数据库和图数据库中搜索和利用连接的机制上。在关系数据库中,在运行查询之前,表与表之间是没有关联的。如果在一个表中声明并强制执行了一个外键来引用另一个表,则外键列的值将对应关联表中的主键值。这意味着两个不同的表存储了重复的数据,而你仍然需要执行搜索来寻找那些相匹配的记录。
想象一个用于跟踪客户的购买记录的简单数据库。我们有三个表:Person(人)、Item(物品)和Purchases(购买记录),如图1-3所示。假设我们想要找到Person B的所有购买记录。因为Purchases表是按日期而不是按人组织的,所以我们需要扫描整个表来找到Person B的购买记录。对于大型数据库来说,这样的操作是非常低效的。
图1-3:Person-Purchases-Item数据库的关系表结构
针对关系数据库人们提出了一个解决方案:二级索引。就像参考书的索引可以告诉我们某些关键字出现在哪几页一样,表索引可以告诉我们某些列值出现的行地址。图1-4概述了Purchases表的PID(Person ID)和IID(Item ID)列的索引。基于索引,我们知道了Person B的购买记录在表中的第4、6、8和10行。然而,在此解决方案中,我们仍然需要做一些权衡。创建和维护索引是需要时间和存储空间的,而且访问索引比直接访问目标数据行还要多出一个额外步骤,且索引本身就是一个表,因此在所有人中找到Person B的速度可能并没有多快。
没有索引:
1.读取Purchases表中的每一行(速度慢且不可扩展)。
有索引:
1.转到Purchases表的二级索引表。
2.找到感兴趣的行(可能很快)。
3.使用索引。
图1-4:Purchases表的二级索引
由于连接已经存在,因此图数据库或图分析平台消除了在查找连接时需要搜索表格和构建索引的问题。
在图中,边直接指向其顶点。不需要遍历表,也不需要建立额外的索引结构。虽然对于单个连接来说,速度上的差异可能不大,但当需要重复此操作以跨越一系列连接并需要连接许多数据记录(例如整个表)时,图的速度可以快数百倍。例如,假设我们要处理以下问题:“找到那些购买了你刚刚购买的物品的人所购买的其他物品。”图1-5对此情景进行了展示,其中“你”是Person A:
1.Person A购买了Item 1。
2.Persons B、C和D也购买了Item 1。
3.Persons B、C和D还购买了Item 2、3、4和5。
对于图来说,这是一个非常简单的三跳查询。为了处理这个问题,我们总共遍历了9个顶点和11条边。
在基于表的系统中,处理以上问题需要三个表连接。虽然好的查询优化和索引能减少大量的工作,使表连接的效率接近于非常高效的图模型,但代价是需要在数据表和索引之间来回执行索引查找。而图查询不需要索引,因为图中已经内置并优化了连接。
图1-5:Person-Purchases-Item数据库的图结构
需要注意的是,只有在“原生”图系统上才能完全体现图的性能优势,因为它们从底层就被设计为图。我们也可以在表格数据库上构建图系统。这种组合能像图一样工作,但不会得到像图一样优异的性能。