将大查询分为多个小查询是否更好?


13

在某些情况下,需要进行非常大的查询才能将多个表及其中的子选择语句连接在一起以产生所需的结果。

我的问题是,我们应该考虑使用多个较小的查询,并通过多次查询数据库来将逻辑操作带入应用程序层,还是一次完成所有查询就更好了?
例如,考虑以下查询:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

最好的方法是什么?

Answers:


14

在这里,我将无法通过datagod来处理大型和复杂的查询。我认为这些只有在杂乱无章的情况下才是问题。从性能角度来看,这些几乎总是更好的,因为计划者在获取信息方面有更多的自由。但是,在编写大型查询时确实要牢记可维护性。总的来说,我发现即使单个查询持续进行200多行,简单,结构良好的SQL仍易于调试。这是因为通常您对要处理的问题有一个很好的了解,因此查询中仅需要检查几个区域。

当SQL结构崩溃时,将出现维护问题IME。子选择中的冗长而复杂的查询会削弱可读性和故障排除功能,内联视图也会如此,长查询中应避免这两种情况。相反,如果可以的话,使用VIEW(请注意,如果您使用的是MySQL,则视图不能很好地执行,但是在大多数其他数据库上,它们可以执行),并在不起作用的地方使用通用表表达式(MySQL不支持这些表达式)顺便说一句)。

从保持可维护性和性能的情况来看,长时间的复杂查询在将where子句保持简单的情况下以及使用联接而不是子选择的情况下能做的尽可能多的情况下都很好地工作。目的是使它不显示“记录”,从而在查询中为您提供一些非常具体的位置进行检查(它是被丢弃在联接中还是在where子句中过滤掉了?),因此维护团队可以实际维护东西。

关于可伸缩性,请记住规划器具有更大的灵活性,这也是一件好事...。

编辑:您提到这是MySQL,因此视图不太可能表现得那么好,并且CTE毫无疑问。此外,给出的示例不是特别冗长或复杂,因此没有问题。


注意:我的查询(不在MySQL中,但仍然...)足够长且复杂,以至于生成的查询计划不是最佳的。在这些情况下,您确实可以获得更快的结果,将一个极其复杂的查询分解为两个不那么复杂的查询。也就是说,这种情况很少见,我通常会编写复杂的查询并找出是否存在问题,而不是先行将查询分成较小的块。
RDFozz

8

作为必须支持/清理这些大而复杂的查询的人,我想将它们分解成几个小而易于理解的块要好得多。从性能的角度来看,并不一定会更好,但是至少您要给SQL一个更好的机会来提出一个好的查询计划。

让跟随您的人们的生活更轻松,他们会对您说好话。加倍努力,他们会诅咒你。


2
但是,一串简单查询的缺点是它们之间的状态会发生很大变化,从而使应用程序的整体调试更加复杂。即,您通常可以将大型SQL查询调试为树形,但是应用程序代码通过检查语句状态变化的语句来调试语句。真正的问题与以下事实有关:子选择和内联视图也是它们自己的树....
克里斯·特拉弗斯

就我而言,唯一需要管理数据库和代码的人就是我自己。大部分我的问题是关于性能点的查询。
Hamed Momeni

你们必须看看我编写大型批处理过程的方式。将事情分解为简单的查询,非常易于阅读。我有偏见,因为我最终试图整理的查询通常超过1000行。
datagod

5

我对2个关键字的查询性能和可伸缩性的2美分:

查询性能: SQL Server并行性已经很好地完成了将查询分解为多线程搜索的工作,因此,我不确定通过对SQL Server进行查询会发现多少查询性能改进。您将必须查看执行计划,以查看执行时获得的并行度,并比较两种方式的结果。如果最终不得不使用查询提示来获得相同或更好的性能,那么IMO则不值得这样做,因为以后查询提示可能不是最佳选择。

可伸缩性: 按照datagod的说明,读取查询可能会更容易,如果您也可以在其他区域使用新查询,则将其分解为单独的查询是有意义的,但是如果您也不想将其用于其他调用,那么它将存储更多的proc来管理一项任务,并且IMO不会对可伸缩性做出任何贡献。


2
RE:“ SQL Server”参考,尽管OP尚未指定任何特定的RDBMS,但我怀疑它们是基于MySQL的LIMIT
Martin Smith,

@MartinSmith您正确地怀疑。它是MySQL。
Hamed Momeni

2

有时,别无选择,只能将大/复杂查询拆分为小查询。确定该内容的最佳方法是在EXPLAINSELECT语句中使用statement。您的数据库要获取数据的跟踪/扫描次数是EXPLAIN查询返回的“行”值的乘积。在我们的例子中,我们有一个查询联接了10个表。对于特定记录,跟踪记录达到了409M,它记录了我们的数据库并将我们的数据库服务器的CPU使用率提高了300%以上。通过更快地拆分查询,我们能够检索相同的信息。

因此,简而言之,在某些情况下,拆分复杂/大查询是有意义的,但在其他情况下,则可能会导致许多性能或可维护性问题,因此应逐案处理。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.