回到我们之前的数据库字段设计,我们知道 parentid 可以和 id 字段结合来输出无限级分类的输出,还能用来表示节点间的关系。
这种设计用得很普遍,而且是最省存储空间,但是却不是最有效率的。比如现在我们有这么一个需求,需要查询指定深度节点时就会遇到问题。因为是采用递归(递归的效率你懂的)的方法,我们需要通过递归来逐层展开才能获取到所有该层的节点,然后再在其中进行查询实在既浪费时间又浪费空间。那么有没有更好的做法呢?
现在再来看看我的设计,增加了两个字段:depth 和 parentid_list。
现在输出树状结构:
观察层级关系字段 parentid_list,和深度字段 depth,维护它们其实并不会很费力,因为有迹可寻的,用程序自动维护也是可以的。但是在查询的时候这两个字段却能给我们带来很大的便利,比如我们需要查询所有第三层的节点:
mysql> SELECT * FROM categories WHERE depth = '3'; +----+---------------+---------+----------+---------------+-------+-------+----------+ | id | name | xname | parentid | parentid_list | depth | state | priority | +----+---------------+---------+----------+---------------+-------+-------+----------+ | 3 | 计算机/互联网 | NULL | 2 | 1,2,3 | 3 | 1 | 0 | | 4 | 医学 | NULL | 2 | 1,2,4 | 3 | 1 | 0 | | 5 | 自然与科学 | NULL | 2 | 1,2,5 | 3 | 1 | 0 | | 8 | 笔记本 | NULL | 7 | 6,7,8 | 3 | 1 | 0 | | 9 | 平板电脑 | NULL | 7 | 6,7,9 | 3 | 1 | 0 | | 10 | 服务器 | NULL | 7 | 6,7,10 | 3 | 1 | 0 | | 13 | 电饭锅 | cookers | 12 | 11,12,13 | 3 | 1 | 0 | | 15 | 冰箱 | NULL | 14 | 11,14,15 | 3 | 1 | 0 | | 16 | 洗衣机 | Washer | 14 | 11,14,16 | 3 | 1 | 0 | +----+---------------+---------+----------+---------------+-------+-------+----------+ 9 rows in set
再比如我们要查询“家用电器”节点的“大家电”节点下的所有子节点,则可以这么写:
mysql> SELECT * FROM categories WHERE parentid_list LIKE '%11,14,%'; +----+--------+--------+----------+---------------+-------+-------+----------+ | id | name | xname | parentid | parentid_list | depth | state | priority | +----+--------+--------+----------+---------------+-------+-------+----------+ | 15 | 冰箱 | NULL | 14 | 11,14,15 | 3 | 1 | 0 | | 16 | 洗衣机 | Washer | 14 | 11,14,16 | 3 | 1 | 0 | +----+--------+--------+----------+---------------+-------+-------+----------+ 2 rows in set
换作用递归来实现,就可能没那么高效,而且也没有这么直观。这样做的道理就在于,通过增加冗余信息来提高检索速度,同时这些冗余信息非常容易维护所以不容易因为操作不慎而导致信息不一致。
当然我的设计并不完善,上面仅仅只谈了益处,如果你觉得这个设计不好,也可以只使用普遍使用的递归方式。
现代魔法 推荐于 2013-02-27 10:23