存储和查询树的最有效方法是什么?

时间:2009-05-07 20:21:15

标签: database-design

我需要分析1 TB +的Web访问日志,特别是我需要分析与请求的URL和URL子分支(子分支)相关的统计信息。如果可能的话,我希望查询能够在数据的小子集上快速进行(例如,1000万个请求)。

例如,给定访问日志并请求以下URL:

/ocp/about_us.html
/ocp/security/ed-209/patches/urgent.html
/ocp/security/rc/
/ocp/food/
/weyland-yutani/products/

我想做一些问题,例如:

  • 计算'/'下面所有内容的请求数量。
  • 与上述相同,但仅计算/ ocp / security
  • 下的子节点请求
  • 返回前5个最常请求的网址。
  • 与上述相同,除了任意深度的组,

e.g。对于上面的上一个查询,数据的深度2将返回:

2: /ocp/security/
1: /ocp/
1: /ocp/food/
1: /weyland-yutani/products/

我认为理想的方法可能是使用列DB并对URL进行标记,以便URL中的每个元素都有一列。但是,如果可能的话,我真的想找到一种方法来使用开源应用程序。 HBase是一种可能性,但查询性能似乎太慢而无法用于实时查询(另外,我真的不想进行重新实现SQL的业务)

我知道有这种类型的分析有商业应用程序,但出于各种原因我想自己实现。

5 个答案:

答案 0 :(得分:13)

在投入大量时间在关系数据库之上设计分层数据结构之前,请考虑阅读Bill Karwin在优秀演示文稿 SQL Anti-Patterns Strike Back 中的"Naive Trees" section (starting at slide 48)。 Bill概述了以下开发层次结构的方法:

  1. 路径枚举(幻灯片55)
  2. 嵌套集(幻灯片58)
  3. 关闭表(幻灯片68)

答案 1 :(得分:3)

树在数据库中通常效率不高。我的意思是:如果你设计的树真的是递归的,项目指向他们的父母,你会得到很多查询来找到所有的子节点。

但您可以根据需要优化树。

将网址的任何部分放入列都不是一个坏主意。您需要将深度限制为一定数量的子节点。你可以在任何列上都有索引,这使得它非常快。

对这种结构的查询非常简单:

Select count(*) From Hits where node1 = 'ocp' AND node2 = 'security';

制作访问统计信息:

SELECT node1, node2, count(*) as "number of hits"
FROM hits 
GROUP BY node1, node2
ORDER BY count(*) DESC

你会得到

node1            node2        number of hits
'ocp'                        23345
'ocp'            'security'   1020
'ocp'            'food'        234
'weyland-yutani' 'products'     22

您也可以按原样存储网址并使用正则表达式进行过滤。这更灵活,但速度更慢,因为您没有索引。您只需要限制网址的整个长度,而不是子节点的数量。

我认为你可以用任何足以存储大量数据的数据库来做到这一点。例如MySql。

答案 2 :(得分:2)

Stephane Faroult的书The Art of Sql有一个非常出色的章节(7 - 处理分层数据),它解释和比较了使用关系数据库存储和查询树的3种方法。

如果你正在进行严肃的,工业化的实施,那么研究这一章将花费时间。

答案 3 :(得分:1)

我认为存储此类数据的最有效方法是在零件爆炸(或层次结构)表中。

零件爆炸表由三列组成:标识,父级和描述。对于示例数据,表格如下所示:

Identity Parent Description
0        Null   ocp
1        0      about_us.html
2        0      security
3        2      ed-209
4        3      patches
5        4      urgent.html
6        2      rc
7        0      food
8        Null   weyland-yutani
9        8      products

在填充URL(爆炸)表时,填充一个记录每个URL的叶子的表。从示例数据:

 Leaf ID
-------
1
5
6
7
9

我相信你可以从这两个表开始回答你的所有问题。

答案 4 :(得分:0)

您可能希望签出SQL Server 2008中的HIERARCHYID数据类型或Oracle中的等效数据类型。