【发布时间】:2013-04-01 08:14:37
【问题描述】:
我有 6 张桌子。在本例中,这些都是简化的。
user_items
ID | user_id | item_name | version
-------------------------------------
1 | 123 | test | 1
data
ID | name | version | info
----------------------------
1 | test | 1 | info
data_emails
ID | name | version | email_id
------------------------
1 | test | 1 | 1
2 | test | 1 | 2
emails
ID | email
-------------------
1 | email@address.com
2 | second@email.com
data_ips
ID | name | version | ip_id
----------------------------
1 | test | 1 | 1
2 | test | 1 | 2
ips
ID | ip
--------
1 | 1.2.3.4
2 | 2.3.4.5
我希望实现以下目标。
用户 (123) 拥有名为“test”的项目。这是给定条目所需的基本信息。
我们的“数据”表中有数据,当前版本为 1,因此我们的 user_items 表中的版本也是 1。这两个表通过名称和版本链接在一起。设置是这样的,因为用户可能有一个我们没有数据的项目,同样可能有一个我们有数据但没有用户拥有的项目..
对于每个项目,还有 0 个或多个相关联的电子邮件和 ips。这些对于许多项目来说可能是相同的,因此我们拥有 data_emails 和 data_ips 表,它们根据 email_id/ip_id 和各自的 ID 列分别链接到 emails 和 ips 表,而不是一遍又一遍地复制实际的 email varchar。
邮件和ips通过项目名称和版本号再次与数据版本关联。
我的第一个问题是这是一个很好/优化良好的数据库设置吗?
我的下一个查询和主要问题是加入这个复杂的数据结构。
我拥有的是:
PHP
- get all the user items
- loop through them and get the most recent data entry (if any)
- if there is one get the respective emails
- get the respective ips
根据用户项目的数量,这算作 3 个查询还是基本上无限?
我相信上述方法效率低下,因此我想将我的设置压缩为使用一个查询来获取相同的数据。
我通过以下代码实现了这一点
SELECT user_items.name,GROUP_CONCAT( emails.email SEPARATOR ',' ) as emails, x.ip
FROM user_items
JOIN data AS data ON (data.name = user_items.name AND data.version = user_items.version)
LEFT JOIN data_emails AS data_emails ON (data_emails.name = user_items.name AND data_emails.version = user_items.version)
LEFT JOIN emails AS emails ON (data_emails.email_id = emails.ID)
LEFT JOIN
(SELECT name,version,GROUP_CONCAT( the_ips.ip SEPARATOR ',' ) as ip FROM data_ips
LEFT JOIN ips as the_ips ON data_ips.ip_id = the_ips.ID )
x ON (x.name = data.name AND x.version = user_items.version)
为了达到这一点,我已经阅读了大量的资料,并且不知疲倦地工作。 这可以按我的要求工作 - 这个问题旨在澄清使用它的好处是什么?
我不得不使用子查询(我相信?)来获取 ips,因为以前它是乘以结果(我相信基于复杂的连接)。我想这个子查询的工作原理是我的主要困惑。
问题摘要。
-我的数据库设置是否适合我的使用?任何改进将不胜感激。任何能帮助我扩展知识的有用资源都会很棒。
-我的 sql 中的子查询实际上是如何工作的 - 查询在做什么?
- 继续使用左连接是否正确 - 我想返回用户项,如果适用于右连接,则返回空值。
-我是否实质上用 2 替换了可能无限数量的查询?这真的有什么不同吗?以上可以改进吗?
-鉴于当我更新数据表中项目的版本时,我知道必须更新 user_items 表中的版本,所以我现在还有一些更新查询要做。这种设置在实践中是否值得权衡?
感谢任何帮助我更好地理解这一点的人!
【问题讨论】:
标签: mysql database database-design join query-optimization