2008年11月20日

树形结构数据的数据表设计

作者 非鱼

程序中用到树形结构的地方有很多,比如自定义文章分类,允许用户无限级添加子分类,比如用户交流的时候的回复,可以对回复进行回复。树形结构可以完全避免让用户的逻辑思维和使用习惯受程序的限制,最大限度的给用户自由,实现对数据的最大利用。

对于以行和列为基础来保存数据的关系形数据库而言,无法直接保存树形的数据,所以必须以其它的方式来实现。

最基本的方式就是保存一个ParentID,显示每条记录的时候去它的下级内容,以递归的形式把树显示出来。这是最简单的逻辑,而且实现起来不复杂,代码写出来也很容易阅读和理解,而且对条目数量也没有任何限制。但是如果每条记录都要执行一下Select,无疑会给数据库造成巨大的压力。即便一次读到数据库里,在内存中一次次的遍历,也会非常浪费CPU资源。

另外一个方式是给每个对象加一个排序字段,让数据在取出来的时候就直接排成按照树形结构的顺序取出来,在显示的时候也无需多次遍历,只要逐条输出就可以,只要根据排序字段和深度来计算它的缩进深度就可以了。

通常的排序字段使用一个简单的字符串即可,比如第一条记录的值为01,第二条为02,第一条的下级内容为0101,0102,依次类推。从数据库中取出的时候,数据库对字符串字段的排序是以字节所代表的值的大小来排的,所以排序之后的顺序就是01/0101/0102/02/0201这个样子。显示的时候这一个值就可以表示出它的上级和它的深度,相当方便。但是这种方式的一个主要坏处是内容的条数受限制,如果每一级用两位数字来表示,那同一级最多就只允许99条内容。用三位就是999条,一旦超出,整个逻辑就被破坏了。所以使用之前需要考虑清楚你所容许的最大条数是多少。(这个字段不止限于数字,同样可以用字母,比如009之后是00A,一直到Z,那么三位所允许的条数限制就是36*36*36,也就是46656条。如果用四位,就达到了168万条,通常这已经足够了。)每层的条目有限制,但是总的层数却是没有限制的,因为可以用nvarchar(max)来保存这个字段,字段长度不限。所以理论上你每一层给它10位也没问题,这样每层的条目限制就成了36的10次方,已经足够多了。

还有一种排序字段是使用数字,比如这篇文章http://www.cnblogs.com/zhuor/archive/2006/08/26/487095.html,但是这篇文章的使用方式有个问题,新的回复会出现在同一级回复的最前面。如果用于回复表,这个显示顺序是很奇怪的。但是让小数不断的除以2,也会受到float的小数点容量限制。

所以,目前我们认为,最好的方式还是使用字符串。