数据库设计 - 类别和子类别

时间:2015-07-25 06:12:16

标签: sql-server database categories database-performance

我需要对与黄金页面有点类似的东西实施分类和子分类。

假设我有下表:

类别表

CategoryId, Title
10, Home
20, Business
30, Hobbies

我有两个选项可以对子分类进行编码。

选项1 - 子类别ID在仅限类别中是唯一的:

子类别表

CategoryId, SubCategoryId, Title
10, 100, Gardening
10, 110, Kitchen
10, 120, ...
20, 100, Development
20, 110, Marketing
20, 120, ...
30, 100, Soccer
30, 110, Reading
30, 120, ...

选项2 - 子类别ID是唯一的OVERALL:

子类别表

CategoryId, SubCategoryId, Title
10, 100, Gardening
10, 110, Kitchen
10, 120, ...
20, 130, Development
20, 140, Marketing
20, 150, ...
30, 160, Soccer
30, 170, Reading
30, 180, ...

选项2听起来更容易从表中获取行 例如:SELECT BizTitle FROM tblBiz WHERE SubCatId = 170

而使用选项1我必须写下这样的内容:

SELECT BizTitle FROM tblBiz WHERE CatId = 30 AND SubCatId = 170

,即包含额外的AND

但是,选项1更容易手动维护(当我需要更新和插入新的子类别等时,我认为它更令人愉悦。

有什么想法吗?选项2在效率方面是否值得麻烦?有没有与这个常见问题相关的设计模式?

3 个答案:

答案 0 :(得分:13)

我会使用这种结构:

IDENTITY

详细说明:

  • 只使用一个表格,引用自己,以便您可以拥有无​​限深度的类别
  • 使用技术ID (使用SELECT BizTitle FROM tblBiz WHERE ParentId = 3 AND CategoryId = 11 或类似内容),以便您可以拥有10个以上的子类别
  • 如果需要,为类别编号添加人类可读单独字段

只要你只使用两个级别的类别,你仍然可以这样选择:

hierarchyid

SQL Server的新parent功能看起来很有前景:https://msdn.microsoft.com/en-us/library/bb677173.aspx

我不喜欢嵌套集模型

  • 嵌套集模型中插入和删除项目非常复杂,需要昂贵的锁定。
  • 如果将rght字段与外键约束结合使用,则可以轻松创建被禁止的不一致
    • 如果lft 更低而不是rght
    • ,则可能会出现不一致
    • 如果某个值在多个 lftJul 24, 2015 9:56:05 AMorg.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@580283d3: startup date [Fri Jul 24 09:56:05 IST 2015]; root of context hierarchy Jul 24, 2015 9:56:05 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [Beans.xml] Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [Beans.xml]; nested exception is java.io.FileNotFoundException: class path resource [Beans.xml] cannot be opened because it does not exist at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:452) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.sj.beans.MainApp.main(MainApp.java:12) Caused by: java.io.FileNotFoundException: class path resource [Beans.xml] cannot be opened because it does not exist at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330) ... 13 more 字段中显示
    • ,则可能会出现不一致
    • 如果您创建间隙
    • ,则可能会出现不一致
    • 如果您创建重叠
    • ,则可能会出现不一致
  • 嵌套集模型在我看来更多复杂,因此不那么容易理解。当然,这绝对是主观的。
  • 嵌套集模型需要两个字段,而不是一个 - 因此会占用更多磁盘空间。

答案 1 :(得分:7)

管理分层数据有一些方法。其中最重要的一个是Nested Set Model

See here用于实施。

甚至像joomla这样的内容管理系统也使用这种结构。

答案 2 :(得分:2)

我建议使用选项1 - 在类别中保持子类别唯一。假设我有两类不相关的项目:

  • 水果
  • 颜色

对于每个我想要一个子类别

  • 水果

    • 苹果
  • 颜色

请注意,Orange是每个类别中的子类别。虽然名称相同,但它的功能却截然不同。 (我们没有考虑到橙色水果颜色为橙色的可能性)

通过这种设计,如果有人改变主意并希望将Orange重命名为Oranges,那很好。它很容易在不影响颜色下的橙色子类别的情况下进行更改。

如果您的UI构建方式使Marketing可以控制Colors的子类别而Production可以控制Fruits的子类别,则此设计将允许Marketing使用其子类别而不会超越Production的子类别。