我目前在一个网站上工作,其中将包含一个产品目录.我对数据库设计有点陌生,所以我正在寻找如何最好地做到这一点的建议.我熟悉关系数据库设计,所以我理解"多对多"或"一对多"等(在大学里修过很好的数据库课程).以下是一个项目分类的示例:

Propeller -> aircraft -> wood -> brand -> product.

与其try 写我到目前为止所拥有的,不如快速浏览一下我从phpmyadmin designer功能创建的这张图片.

alt text http://www.usfultimate.com/temp/db_design.jpg

Now, this all seemed fine and dandy, until I realized that the category "wood" would also be used under propeller -> airboat -> (wood). This would mean, that "wood" would have to be recreated every time I want to use it under a different parent. This isn't the end of the world, but I wanted to know if there is a more optimal way to go about this.

另外,我尽量保持这件事的动态性,这样客户就可以根据他的需求变化来组织他的目录.

*编辑.正在考虑创建一个"标签"表.因此,我可以将标签"wood"或"metal"或"50inch"指定给多个项目的1.我仍然会为主要的分类保留一个育儿类型的东西,但这样分类就不必太深入,也不会有重复.

推荐答案

First, the user interface:作为用户I hate在以strictly hierarchical方式组织的目录中搜索产品.我从来不记得"异国情调"的产品属于哪个子类……,这迫使我浪费时间go 探索"有前途的"类别,结果却发现它是以一种奇怪的方式(至少对我来说是这样)归类的.

Kevin Peno建议是一个好建议,被称为101.正如Marcia BatesAfter the Dot-Bomb: Getting Web Information Retrieval Right This Time中所写,".. faceted classification is to hierarchical classification as relational databases are to hierarchical databases. ..".

本质上,faceted search允许用户从他们喜欢的任何"方面"开始搜索目录,并允许他们在搜索过程中 Select 其他方面来过滤信息.请注意,与标签系统通常的构思相反,没有什么可以阻止您按层次组织这些方面.

要快速理解分面搜索是怎么回事,在The Flamenco Search Interface Project - Search Interfaces that Flow100种搜索方式可供探索.

Second, the application logic: Manitra提出的建议也是一个很好的建议(据我所知),即以不同的关系分隔树/图的nodeslinks.他所说的"祖先表"(这是一个直观得多的名称)被称为transitive closure of a directed acyclic graph (DAG)(可达性关系).正如马尼特拉所说,除了性能,它还大大简化了查询.

But对于这样的"祖先表"(可传递闭包),我建议使用view,这样更新是实时的和增量的,而不是按批处理作业(job)定期更新.在我对query language for graph sets: data modeling question的回答中提到的论文中有SQL代码(但我认为它需要稍微修改一下以适应特定的DBMS).具体来说,请看Maintaining Transitive Closure of Graphs in SQL(.ps-postscript).

Products-Categories relationship

马尼特拉的第一点也值得强调.

他说的是,产品和类别之间存在多对多关系.即:每个产品可以在一个或多个类别中,每个类别中可以有零个或多个产品.

给定关系变量(relvars)产品和类别,例如,这种关系可以表示为至少具有属性P#和C#的relvar PC,即外键关系中的产品和类别号(标识符)与相应的产品和类别号.

这是对类别层次 struct 管理的补充.当然,这只是一个设计草图.

On faceted browsing in SQL

实现"分面浏览"的一个有用的概念是relational division,甚至relational comparisons(见链接页面底部).也就是说,将PC(产品类别)除以从用户(方面导航)中 Select 的(不断增长的)类别列表,一个人只能获得此类类别中的产品(当然,类别被认为是相互排斥的,否则 Select 两个类别一个人将获得零产品).

基于SQL的DBMS通常缺少这种运算符(除法和比较),因此我在下面给出一些有趣的文章来实现/讨论它们:

以此类推.

我不会在这里详细介绍,但是类别、层次 struct 和方面浏览之间的交互需要特别注意.

A digression on "flatness"

我简单地看了一下Pras,Managing Hierarchical Data in MySQL链接的那篇文章,但在导言中的这几行之后我停止了阅读:

Introduction

大多数用户在某个时候都有

为了理解为什么这种对关系平坦性的坚持是just nonsense,想象一个three dimensional Cartesian coordinate system中的立方体:它将由8个坐标(三元组)标识,比如P1(x1,y1,z1),P2(x2,y2,z2)...,P8(x8,y8,z8)[这里我们不关心这些坐标的约束,所以它们实际上代表一个立方体].

现在,我们将把这组坐标(点)放入一个关系变量中,并将这个变量命名为Points.我们将Points的关系值作为下表:

Points|  x |  y |  z |
=======+====+====+====+
       | x1 | y1 | z1 |
       +----+----+----+
       | x2 | y2 | z2 |
       +----+----+----+
       | .. | .. | .. |
       | .. | .. | .. |
       +----+----+----+
       | x8 | y8 | z8 |
       +----+----+----+

这个立方体是不是仅仅因为用表格的方式来表示就被"压扁"了?关系(值)和它的表格表示法是一样的吗?

关系变量假定n维离散空间中的点集为值,其中n是关系属性("列")的数量.对于n维离散空间来说,"扁平"意味着什么?就像我在上面写的那样,简直是胡说八道.

不要误会我的意思,SQL确实是一种设计糟糕的语言,基于SQL的DBMS充满了特性和缺点(NULL、冗余等),特别是糟糕的DBMS as-umb-store类型(没有引用约束、没有完整性约束,等等).但这与关系数据模型幻想中的局限性无关,相反:他们越远离它,结果就越糟糕.

具体地说,一旦您理解了关系数据模型,它在表示任何 struct (甚至是层次 struct 和图形)方面都不会有任何问题,正如我在上面提到的已发表论文的引用中所详细描述的那样.即使是SQL,如果您掩饰它的不足之处,也会错过更好的东西.

On the "The Nested Set Model"

我浏览了一下睡觉的that article值,我对这种逻辑设计并不是特别感兴趣:它建议将两个不同的实体nodeslinks混为一谈,这可能会造成尴尬.但我不想更彻底地分析这个设计,抱歉.


EDIT:斯蒂芬·埃格蒙特(Stephan Eggermont)在下面的 comments 中反对"The flat list model is a problem. It is an abstraction of the implementation that makes performance difficult to achieve. ...".

现在,我的观点是,确切地说,

  1. 这个"扁平列表模型"是一个fantasy:仅仅因为一个人将关系布局(表示)为表格("扁平列表")并不意味着关系就是"扁平列表"(一个"对象",它的表示不是一回事);
  2. 逻辑表示(关系)和物理存储详细信息(水平或垂直分解、压缩、索引(散列、b+树、r-树等)、群集、分区等)关系数据模型(RDM)的要点之一是将逻辑模型与"物理"模型解耦(对DBMS的用户和实现者都有好处);
  3. 性能是物理存储细节(实现)和逻辑表示的直接结果(Eggermont的 comments 是logical-physical confusion的classic 示例).

RDM模型不以任何方式约束实现;您可以随意实现元组和关系.关系是not necessarily个文件,元组是一个文件的not necessarily条记录.这样的通信是哑巴direct-image implementation.

不幸的是,基于SQL的DBMS实现are经常是愚蠢的直接映像实现,并且它们在各种场景中的性能都很差-OLAP/ETL产品就是为了弥补这些缺点而存在的.

这种情况正在慢慢改变.有一些商业和自由软件/开源实现最终避免了这个基本trap :

当然,not的要点是必须存在一个"最佳"的物理存储设计,但是任何物理存储设计都可以由基于关系代数/演算(SQL就是bad个例子)的declarative language抽象出来,或者更直接地基于逻辑编程语言(例如,Prolog-请参见我对"prolog to SQL converter"问题的回答).一个好的数据库管理系统应该是基于数据访问统计数据(和/或用户提示)在飞翔上更改物理存储设计.

最后,在埃格蒙特的 comments 中,声明"The relational model is getting squeeezed between the cloud and prevayler."是另一种胡说八道,但我不能在这里给出反驳,这个 comments 已经太长了.

Database相关问答推荐

什么是 CREATE VIEW IF NOT EXISTS in postgresql

add_index 到数据模型 - Ruby on Rails 教程

在 bindParam 中使用 LIKE 进行 MySQL PDO 查询

在 model.save() 中处理竞争条件

使用 Mongoose 删除索引的推荐方法是什么?

Followers/following 关注者表数据库 struct

Entity Framework:如何检测对数据库的外部更改

Java 数据库连接池(BoneCP vs DBPool vs c3p0)

在 Oracle 的 Check 语句中使用子查询

使用 2 个进程处理数据库

如何在 Play 2.0 中 for each 环境设置不同的数据库?

内存数据库和磁盘内存数据库的区别

在 SQL SERVER 中监视 SQL 查询的进度

我应该不断地open()和close() SQL 数据库还是让它保持打开状态?

此平台不支持 LocalDB

使用 PDO 获取单行单列

不带 WHERE 子句的 UPDATE 查询

Oracle 的免费桌面客户端?

一个表可以有两个外键吗?

python3k中的sqlite3中的cursor.rowcount总是-1