【问题标题】:Table Design- Mysql表设计-Mysql
【发布时间】:2012-06-10 16:38:28
【问题描述】:

让我试着解释一下我正在处理的应用程序的情况,

我有近 7 个类别,比如说 A、B、C、D、E、F 和 G。这些类别在 DB 端没有任何表格。现在用户从这 7 个类别中选择一些类别,比如说 C,所以在 C 类中,我有另一组子类别,即 C1、C2、C3 到 C30。现在假设用户选择 C2,对于 C2 子类别,我在数据库中有一个表,一旦用户通过前端输入所有数据,就会插入该表.现在C2表有8列,即c2t1id,c2t2 ....c2t8。它还具有自动增量 id 列,该列为该表的每个插入获取自动增量以及该表的主键。

现在我的问题是,我需要向用户显示他们在所有表格中的应用程序中的所有插入。用户可以在所有 7 个类别中插入,每个类别都有子类别 upt0 30,根据现有设计,这变得接近到 210 张桌子。

现在我的登录表由 id/name/pw 构成。

现在从 db 的角度来看我的设计,我开始觉得这个设计有些缺陷,我开始觉得只是要检索用户的 5 条记录,我需要搜索200+ 长的多选择连接表?

我需要一些提示,说明我应该如何进一步处理。如果需要,我准备重新设计。

【问题讨论】:

    标签: mysql database database-design hierarchical-data


    【解决方案1】:

    听起来您确实需要在继续进行之前检查您的设计。

    与其泛泛而谈,不如说具体。人们在不了解数据细节的情况下很难推荐数据库设计。

    那么,具体告诉我们数据是什么。

    编辑:

    根据您告诉我们的有关您的数据的内容,它看起来像这样:

    USER
    ----------------------
    ID (PK) INTEGER AUTOINCREMENT NOT NULL
    EMAIL (PK) VARCHAR(1000) NOT NULL
    FIRST_NAME VARCHAR(50) NOT NULL
    LAST_NAME  VARCHAR(50) NOT NULL
    ENCRYPTED_PASSWORD ....etc
    
    
    POST
    --------------
    ID (PK) INTEGER AUTOINCREMENT NOT NULL
    USER (FK) INTEGER NOT NULL
    CONTENT TEXT NOT NULL
    DATE_POSTED TIMESTAMP NOT NULL
    DATE_EDITED DATETIME NOT NULL
    
    
    POST_CATEGORIES
    --------------------
    ID (PK) INTEGER AUTOINCREMENT NOT NULL
    CATEGORY_ID (FK) INTEGER NOT NULL
    POST_ID (FK) INTEGER NOT NULL
    
    CATEGORY (hierarchal table)
    ------------------------------
    ID (PK) INTEGER AUTOINCREMENT NOT NULL
    PARENT_ID INTEGER
    CATEGORY_NAME VARCHAR(200) NOT NULL
    

    请注意,CATEGORY 表使用的是简单的代理商列表模型。其他类型的模型是可能的。请参阅优秀的 Managing Hierarchal Data in MySQL 文章了解更多详情。

    通过这种设计,获取用户帖子列表将是:

    select * from POSTS where USER = (select ID from USER where FIRST_NAME = 'John' and LAST_NAME = 'Doe');
    

    如果您想添加类别,您也可以加入 POST_CATEGORIES 和 CATEGORY 表。显然这是一个简化的示例,但希望您能看到这种设计如何支持在少数表格中包含数十万或数百万个帖子的数百或数千个类别。

    【讨论】:

    • 嗨 wadesworlds,子类别结构类似于,{cid: INT}, {ctitle: VARCHAR}, {cname: VARCHAR}, {caddr: VARCHAR}, {cph: DOUBLE}, {coffs: VARCHAR}、{ctmaps: VARCHAR}、{ctimg: VARCHAR}、{ctdatetime: DATETIME}。这些是类别 C 的子类别列详细信息。其他类别可能总共有 8 列以上。(我已经开始研究这些模块然而,但我确信它会比这个更多列)。我插入的数据非常简单,它的表单大约有 7 个字段,文件存储在本地磁盘中,路径进入数据库。所以没有 blob 或任何地方都涉及到 clob
    • 我并不是要告诉我们数据类型。我的意思是告诉我们应用程序的作用。它是一个订单跟踪系统吗?是角色扮演游戏吗?是基因测序吗?然后告诉我们数据是什么:“每个玩家可以是 8 个职业之一。每个职业最多可以有 20 个能力”等等……换句话说,描述你要存储的内容。
    • 嗨 wadesworld,我能想到的最接近的例子是 ebay 分类网站或 craglist。如果你看 craglist 或 ebay 分类的设计,我的要求看起来几乎相似。你有主要类别,然后你去子类别,然后您将一些详细信息发布到子类别(发布您需要登录),您的帖子详细信息将被插入到数据库中。到目前为止很好。现在让我们移动用户帐户详细信息,他需要查看他在一个月内完成了多少帖子/day 等,所以显然你需要跟踪他的帖子,这就是我的要求。我应该如何跟踪这个。
    • 嗨Wadesworld,谢谢我得到了我现在应该如何进行的提示。我现在看到了我的设计中的差距。父母和孩子之间没有明确的关系。它像父母一样是硬编码的(通过 ui) 和客户端在子表上插入。当我需要从子表中提取数据时,用户 ID/父表/子表之间没有关系,这就是我空白的原因。所以我从这里的所有这些讨论中了解到,我需要将父表与子表和子表中的每个插入,都需要有与之关联的父 ID 和用户 ID。
    • 这应该可以解决我的设计缺陷。但这里的挑战是我不认为这会减少对子表数量的要求。这里的类别是父类别,子类别是子类别。因为每个孩子将有不同数量的列与它们相关联(想想每个子类别的独特定制),所以显然我担心表格会达到 200 多个,这对某些功能(如进行全局搜索)构成挑战。
    【解决方案2】:

    是的,那个设计是个失败者。 210张桌子?再想想。停止考虑表格和列,并将其表达为您要解决的问题。也许这里不适合使用关系数据库。

    【讨论】:

    • 感谢 Duffymo,但我不认为没有 DB,我可以构建应用程序。我认为 db 是必需的。当时的想法是为子类别表再创建一个列,它会以某种方式将用户与子类别和然后根据该列从子类别中提取数据。但是使用这种方法我也搜索了近 200 个表。除此之外,我对如何优化设计一无所知。
    • 我认为 @duffymo 暗示的是一个 NO-SQL 风格的数据库。
    • 不一定。第一步是从人、业务、术语中识别问题。这样一来,人们就可以开始考虑适合的 db 实现。如果您必须首先考虑 db ,那很好。你只需要接受你需要改变这种方法。
    • 不,我没有首先想到 DB,我通过简单的表创建实现了大部分功能,然后构建客户端和服务器端代码。现在对于少数功能,比如显示用户过去的活动,以及进行全局搜索,我意识到表格彼此不相关,它们是孤立的。这让我意识到出了点问题,这促使我在这里检查。这是我自己的网站,所以设计中有一些元素我正在尝试,有些是我们经常使用的常规东西。
    • 不确定这是否与您的建议有关,只是为了给您一些背景信息。
    【解决方案3】:

    每个节点都有一个表的层次结构不是通常的答案 - 我建议查看this question 的答案,看看是否有任何建议适用于您的问题。

    【讨论】:

    • 不,它与我的不相似。我没有 3 到 4 级的关系。我的很简单,我有父类,然后每个父类都有很多子类(比如 30 个不同列的子类)它),用户可以对孩子进行插入/更新/搜索。用户可以根据父母搜索孩子。我总共有大约 8 个父母,每个父母至少有 30 个孩子。所以它变成了一个父子关系很多。
    【解决方案4】:

    基于您对@wadesworld 的 cmets/解释 这是一个简单的设计,可能会为您指明正确的方向

    我使结构尽可能简单,您可以添加更多列/详细信息以适合您的应用程序,并且我展示了一些示例来说明如何查询数据。

    TABLE: USERS
    ID | USERNAME | PASSWORD
    
    TABLE: CATEGORIES
    ID | CATEGORY_ID | NAME
    
    TABLE: POSTS
    ID | CATEGORY_ID | DESCRIPTION | USER_ID
    
    
    
    // list all top level categories (We use NULL in categories.category_id to indicate it has no parents)
    SELECT * FROM categories WHERE category_id IS NULL;
    
    // list all sub categories for category_id = 2
    SELECT * FROM categories WHERE category_id=2;
    
    // list parent and child categories, for use in a html select
    SELECT parent.id, parent.name, child.id, child.name
      FROM categories AS parent
      JOIN categories AS child ON child.category_id=parent.id
      WHERE parent.category_id IS NULL
    
    // insert a post into category_id=2 for user_id = 1
    INSERT INTO posts (category_id, description, user_id)
      VALUES ('2', 'test post', 1);
    
    // select all posts by user with username=tom
    SELECT * FROM users
     JOIN posts ON posts.user_id=users.id
     JOIN categories ON categories.id=posts.category_id
     WHERE users.username='tom';
    
     // count the number of posts made by tom in each category
     SELECT categories.name, COUNT(*)
       FROM users
       JOIN posts ON posts.user_id=users.id
       JOIN categories ON categories.id=posts.category_id
       WHERE users.username='tom';
       GROUP BY categories.name
    

    【讨论】:

    • 谢谢 Bumperbox,我也从你和 Wadesworld 那里得到了提示。我会在我尝试新模块的这些更改时继续这个线程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 2014-01-12
    • 2012-11-11
    • 2011-04-20
    相关资源
    最近更新 更多