许多(许多)SQL JOIN 与多个查询

Posted

技术标签:

【中文标题】许多(许多)SQL JOIN 与多个查询【英文标题】:Many (many) SQL JOINs vs Multiple queries 【发布时间】:2013-08-29 13:33:17 【问题描述】:

我想我是来问一个你们很多人已经问过自己的问题,我想。我正在创建一个 php 网站,一切都运行顺利,直到我决定用一些测试数据填充我的数据库(真实数据,当应用程序开始真正使用时,它会变得更大)。大多数事情仍然可以正常工作,但一个特定(并且非常重要)的功能开始执行时间为 3 到 4 秒,其中大部分时间都花在了 mysql 服务器上。

交易是这样的:我正在为一所学校构建一个应用程序,它需要包含每天、每个人、每个房间、每个班级的所有时间表和课程。完成了数据库的结构,创建了索引,等等……问题是,由于所有这些数据都是关系型的(并且可以分布在许多表中),因此获取它们的查询可能如下所示:

SELECT field1, field2, etc
FROM schedules AS su
LEFT JOIN schedules_lessons AS sul
    ON sul.ID_SCHEDULE = su.ID
LEFT JOIN schedules_lessons_teachers AS sult
    ON sult.ID_LESSON = sul.ID
LEFT JOIN users AS u
    ON u.ID = sult.ID_TEACHER
LEFT JOIN schedules_periods AS sup
    ON sup.ID_SCHEDULE = su.ID
LEFT JOIN schedules_periods AS sulp
    ON sulp.ID_SCHEDULE = sul.ID_SCHEDULE AND sulp.period = sul.period
LEFT JOIN schools AS s
    ON s.ID = su.ID_SCHOOL
LEFT JOIN schools_buildings AS sb
    ON sb.ID_SCHOOL = s.ID
LEFT JOIN schools_rooms AS sr
    ON sr.ID = sul.ID_ROOM
LEFT JOIN schools_classes AS sc
    ON sc.ID = sul.ID_CLASS

是的,我知道有很多连接。我的问题是:我应该如何在连接数量和数量或查询之间取得最佳平衡?因为我觉得这真的可以改进,但我不知道如何实现它。

大多数表的记录数都在 200 以下,只有课程表可以有更多。最小值接近 5k,最大值可能是 30k 或更多。

【问题讨论】:

在不知道你的架构的情况下很难给出建议,但从你的查询中猜测出来,似乎没有什么问题。为了提高性能,您是否正确索引了所有表中的所有相关字段(示例中的所有外键)?此外,与schedules_periods AS sulp 的第二个连接似乎是多余的,只需将第一个连接更改为LEFT JOIN schedules_periods AS sup ON sup.ID_SCHEDULE = su.ID AND sup.period = sul.period。关于查询长度,您可以使用一些视图来缩短查询。规范化良好的数据库没有任何问题。 这样的东西是 nosql 大放异彩的地方.. 看起来很可怕。 @Eggplant 你好。好吧,事实是(冗余)查询是我用来进行排序工作的一个小技巧。这有点难以解释。这是因为周期是特定于日程的,这意味着它们对于每个日程都是不同的。因此,我不仅要选择与课程相对应的时段,还要选择与整个时间表相对应的时段,同时仍要在课程开始前订购课程。 :) 【参考方案1】:

如果您需要这些信息并且表已正确编入索引,那么您的连接查询应该是提取数据的一种非常合理的方法。您可以通过在查询前添加explain 来检查索引是否正在使用。

当您说“大部分时间都花在 MySQL 服务器上”时,您是否考虑到返回数千行需要时间?您可以尝试执行相同的查询,但将 select . . . 替换为 select count(*) 以查看底层查询性能如何。另一种方法是将order by <something> limit 1 添加到现有查询中——order by 必须在返回结果之前完全处理查询。

最后,如果这只是开始成为一个问题,那么自从它按照您希望的方式工作后发生了什么变化?

【讨论】:

您好,感谢您的回答。好吧,这是从我将一些真实数据插入数据库(创建那些 4k+ 行)开始的。此外,我检查了每个表的 phpMyAdmin,anc 检查了索引,它们都是为这些字段创建的。另外,当我说查询时间时,我实际上只是测量了查询函数在获取结果之前所花费的时间。此外,按照您使用 count(*) 的建议将执行时间降低到 1.5 秒左右。【参考方案2】:

我不是数据库专家,但也许只从应用程序或网页中当前需要的数据库中查询信息是有意义的。 我猜这应该可以在相当短的时间内完成。 然后可以在实际需要时从数据库中查询其余部分。

请注意,数据库服务器正在内存中构建一个大表,所有连接都被合并。如果您的服务器内存太少,则构建此表可能会遇到困难。 (尽管在您的场景中可能并非如此......)

【讨论】:

【参考方案3】:

您应该尽可能让数据库处理连接,并避免进行不必要的查询。理论上这应该是最优的。如果所有连接字段都已编入索引,您的查询似乎很好。 规定的数量并不引人注目,响应时间应该没问题(再次提供所有索引都已创建)。 请记住,您应该很少有返回许多记录的查询(当然报告是例外) - 在应用程序中,您应该通过分页来控制它。

【讨论】:

您好,感谢您的回答。好吧,事实是,实际上没有办法减少我向数据库查询的内容,因为我已经只查询了属于用户请求的时间表的课程。它可能最终最多返回 30 节课。 :) 您好,根据您的信息:返回 30 条记录和执行时间 > 1 秒我会说可能缺少索引,或者您的数据库非常慢。你应该检查执行计划。

以上是关于许多(许多)SQL JOIN 与多个查询的主要内容,如果未能解决你的问题,请参考以下文章

CROSS APPLY 风格与性能

一个大查询与许多小查询?

VB6 - 如何在一次调用中执行多个SQL查询

多个INNER JOIN子查询sql

如何使用多个 JOIN 加速 SQL 查询?

按名称查询报表的 SQL 查询,其中许多列按状态计数