我应该使用哪种分层模型?邻接,嵌套或枚举?

Lay*_*yke 8 mysql enumeration nested-sets adjacency-list

我有一张桌子,其中包含世界上所有地理位置的位置及其关系.

以下是显示层次结构的示例.您将看到数据实际存储为全部三个

  • 枚举路径
  • 邻接清单
  • 嵌套集

数据显然也从未改变过.下面是英格兰布莱顿位置的直接祖先的例子,其中有一个13911的寂寞.

表:( geoplanet_places有560万行) 祖先 大图:http://tinyurl.com/68q4ndx

然后,我有一个名为的表entities.此表存储我想要映射到地理位置的项目.我存储了一些基本信息,但最重要的是我存储了woeid哪个是外键geoplanet_places. 在此输入图像描述

最终该entities表将包含数千个实体.我想要一种能够返回包含实体的所有节点的完整树的方法.

我计划创建一些东西,以便根据实体的地理位置过滤和搜索实体,并能够发现在该特定节点上可以找到多少个实体.

所以如果我的表中只有一个实体entities,我可能会有这样的东西

`地球(1)

英国(1)

英格兰(1)

东萨塞克斯郡(1)

布莱顿 - 霍夫市(1)

布莱顿(1)`

让我们说我有另一个位于德文郡的实体,那么它会显示如下:

地球(2)

联合王国(2)

英格兰(2)

德文(1)

东萨塞克斯(1)......等

(计数)将说明每个地理位置"内部"有多少实体不需要是活的.我可以忍受每小时生成我的对象并缓存它.

目标是,能够创建一个界面,可能开始只显示有实体的国家.

所以喜欢

Argentina (1021),Chile (291),...,United States (32,103),United Kingdom (12,338)

然后,用户将点击某个位置,例如United Kindom,然后将获得作为英国后代的所有直接子节点,并且其中包含实体.

如果United Kindgdom中有32个县,但最终只有23个当你向下钻取时存储了实体,那么我不想显示其他9.它只是位置.

本网站恰如其分地表明,我希望实现的功能: http://www.homeaway.com/vacation-rentals/europe/r5 在此输入图像描述

您如何建议我管理这样的数据结构?

我正在使用的东西.

  • PHP
  • MySQL的
  • Solr的

我计划尽可能快地完成钻孔.我想创建一个无缝的AJAX界面进行搜索.

我也有兴趣知道你建议索引哪些列.

Qua*_*noi 9

通常,层次结构中有三种查询会导致麻烦:

  1. 归还所有祖先
  2. 归还所有后代
  3. 归还所有孩子(直系后代).

这是一个小表,显示了不同方法的性能MySQL:

                        Ancestors  Descendants  Children        Maintainability InnoDB
Adjacency list          Good       Decent       Excellent       Easy            Yes
Nested sets (classic)   Poor       Excellent    Poor/Excellent  Very hard       Yes
Nested sets (spatial)   Excellent  Very good    Poor/Excellent  Very hard       No
Materialized path       Excellent  Very good    Poor/Excellent  Hard            Yes
Run Code Online (Sandbox Code Playgroud)

In children,poor/excellent表示答案取决于您是否将方法与邻接列表混合,即存储parentID在每个记录中.

对于您的任务,您需要所有三个查询:

  1. 所有祖先都展示了地球/英国/德文的东西
  2. 所有孩子都要出示"欧洲目的地"(项目)
  3. 所有后代都显示"欧洲目的地"(计数)

我会选择物化路径,因为这种层次结构很少发生变化(仅在战争,反抗等情况下).

创建一个名为varchar的列path,对其进行索引并使用如下值填充它:

1:234:6345:45454:
Run Code Online (Sandbox Code Playgroud)

数字是适当父母的主键,顺序正确(1欧洲,234英国等)

您还需要一个表levels来保持数字120(或任何您想要的最大嵌套级别).

要选择所有祖先:

SELECT   pa.*
FROM     places p
JOIN     levels l
ON       SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN     places pa
ON       pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':') 
WHERE    p.id = @id_of_place_in_devon
Run Code Online (Sandbox Code Playgroud)

要选择所有孩子和其中的地点数:

SELECT  pc.*, COUNT(pp.id)
FROM    places p
JOIN    places pc
ON      pc.parentId = p.id
JOIN    places pp
ON      pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
        AND pp.id NOT IN
        (
        SELECT  parentId
        FROM    places
        )
WHERE   p.id = @id_of_europe
GROUP BY
        pc.id
Run Code Online (Sandbox Code Playgroud)