【发布时间】:2019-03-28 21:29:04
【问题描述】:
我正在尝试为特定数据结构考虑性能最高的数据库架构。有两个主要实体:课程和主题。 课程是主题的集合。 主题具有视频、资源和视频总时间等字段。
直观地表示这个数据结构:
- Course
|_ ID: 12345
|_ Themes: [A, B] (an array of UIDs)
- Theme A
|_ Courses: [12345,67890] (an array of UIDs)
|_ Videos: [1,2,3,4,5,7] (an array of UIDs)
|_ Resources: [10,11,12] (an array of UIDs)
|_ Video Total Time: 10000 (probably stored as seconds as tinyint field)
- Theme B
|_ Courses: [12345,98765] (an array of UIDs)
|_ Videos: [5,6,7,8] (an array of UIDs)
|_ Resources: [12,13,14] (an array of UIDs)
|_ Video Total Time: 20000 (probably stored as seconds as tinyint field)
我想要实现的是两个表的数据库架构,一个用于Courses,一个用于Themes。想法是让 MySQL 查询获取 Course 并将 Themes 中的所有字段分组。换句话说,当我得到 MySQL 查询的结果时,(使用 PHP)我会得到一个这样的数组或对象:
Array(
'ID' => 12345
'themes' => [A,B]
'videos' => [1,2,3,4,5,6,7,8]
'resources' => [10,11,12,13,14]
'video_total_time' => 30000
)
所以,关键是它们是两个关系数据库。当我向数据库发送请求视频数据的查询时,我需要从所有主题中提取数据,并将它们合并在一起。
由于我不是 SQL / MySQL 方面的专家,所以我在尝试弄清楚的同时尝试了解一点:
1) 这两个实体的最佳数据库模式是什么?课程和主题?专门考虑性能
2) 我可以全部使用 SQL 获取最终数据吗?或者我应该从数据库中提取一些数据,然后用 PHP 解析数据?什么通常更快?
3) 存储 UID 数组的最佳方式是什么?作为字符串?还是有更好的存储方式?
这样做的主要目标是性能。我在不同的数据库架构中拥有此类数据,并与数千种其他类型的数据(WP 数据库、wp_posts / wp_postmeta 表)合并,但现在获取我需要的信息真的很慢。
非常欢迎任何提示和建议!
编辑:已解决!
决定哪个答案最适合我的需求是一个艰难的决定,因为@TimMorton 和@PaulSpiegel 的答案将我们引向相同的道路,但方法略有不同。 Tim 的回答非常有助于理解如何正确设计数据库模式、考虑多对多关系以及如何组织查询。但由于这个问题的主要焦点是提高性能,因此 Paul 的回答更侧重于这一点,包括有关主键和索引的具体细节(这对于提高查询性能至关重要)。
无论如何,我学到了很多关于设计数据库模式的知识。以下是我学到的经验教训:
- 不要试图将所有内容都放入同一个表中:在定义您需要的表之前正确识别实体至关重要。我从两个表开始,分别用于视频和主题。但事实证明,适合我的规范的数据库架构包括视频和资源表。
- 不要将数组存储到列中:使用适当的策略来定义实体之间的关系。如果您有一对一或一对多的关系,请使用实体 ID 和外键。如果您有多对多关系,那么正确的设计模式是创建一个专用表,仅用于创建实体之间的关系。这将允许您在查询中使用 JOIN 子句来将所有数据放在一起。
- 当您考虑性能时,请考虑 INDEX:根据您的表结构,使用索引或复合索引都可以提高查询性能。
- 不要试图在一个大查询中获取所有内容:您当然可以,但是对您需要的数据部分进行单独查询(在我的示例中,一个查询获取课程的所有主题,一个查询获得课程的所有视频,获得课程资源的人)通过代码组织和可读性获得回报。
我不知道我对以上所有内容是否正确,但这是我到目前为止所学到的。希望这对其他人也有帮助。
【问题讨论】:
-
将其视为两个表是错误的。我看到了主题、课程、视频和资源。一个线索是,任何时候你看到一个数组,想想表。例如,视频:视频将具有 id 、标题和运行时间。你不需要一个叫做视频总时间的字段;它只会在您的查询中相加。
-
嘿@TimMorton 感谢您的评论。所以你认为获取我需要的所有数据的最有效的方法是将信息分解到多个表中?为主题设置 video_total_time 字段的想法是更快地获取此信息。但是由于我是 SQL / MySQL 的新手,也许在数据库中查询主题的所有视频,并且他们对所有视频时间进行总和,不会像我想的那么慢?
-
见is-storing-a-delimited-list-in-a-database-column-really-that-bad。然后你可能会意识到你正在设计一个性能灾难。
-
嘿@PaulSpiegel 感谢您的链接,非常有用。就像我说的,我是设计合适的数据库模式的新手。您将如何处理这些关系字段?我应该为每个组合建立一个关系表吗? IOW:一张表用于课程 主题,一张用于主题 视频,一张用于主题 资源?
-
规范化模式每个实体有一个表,每个多对多关系一个表。一对多关系通过子表中的引用(外键)解决(因此这些关系没有额外的表)。据我所知,您没有多对多关系。所以你需要四个表:
courses、themes、video和ressources。
标签: mysql performance