在循环中运行SQL计数(*)查询会更快吗,还是试图将它合并到父查询中?

问题描述:

我有一个SQL查询。在循环中运行SQL计数(*)查询会更快吗,还是试图将它合并到父查询中?

SELECT `shifts`.*, `races`.`race_attrition_rate` 
FROM `shifts` 
JOIN `races` ON `races`.`race_id` = `shifts`.`race_id` 
WHERE `shifts`.`race_id` = 'X' 
AND `shift_deleted` =0 
ORDER BY `shift_name` ASC, `shift_id` ASC 

该查询从数据库中提取志愿者轮班列表。然后我有一个PHP循环,对于上面查询中拉出的每个班次,都运行这个SQL查询。

SELECT COUNT(*) AS `numrows` 
FROM `volunteer_shifts` 
WHERE `shift_id` = 'Y' 
AND `shift_deleted` =0 

因此,如果在第一个查询中拉出5个班次,则第二个查询将运行5次,每次轮班一次。

1)这两个查询可以合并在一起吗?组合代码的样子是什么?

2)将这两个查询合并得更快吗?

3)将它们合并在一起可能会使代码不易读。那么最佳做法是什么?两个可读的查询或一个难以阅读但快速查询?

+0

“更快”没有测量是没有意义的。它快10ms吗?或者一个小时?没有测量,你不能做出真正的决定。 –

2)这两个查询合并在一起快?

单查询将definetely更快,因为没有花在网络活动时间(试想一下,DB位于另一台服务器,这是很常见的情况)

而且独立的查询办法没有按” t允许内置的DB查询优化器完成其工作

1)这两个查询可以合并在一起吗?组合代码的样子是什么?

下面的查询可以为你工作:

SELECT 
    `shifts`.*, 
    `races`.`race_attrition_rate`, 
    (SELECT 
     COUNT(*) AS `numrows` 
    FROM 
     `volunteer_shifts` 
    WHERE 
     `volunteer_shifts`.`shift_id` = `shifts`.`shift_id` 
    AND 
     `shift_deleted` = 0) AS `volunteer_shifts` 
FROM 
    `shifts` 
    JOIN `races` ON `races`.`race_id` = `shifts`.`race_id` 
WHERE 
    `shifts`.`race_id` = 'X' 
AND 
    `shift_deleted` = 0 
ORDER BY 
    `shift_name` ASC, `shift_id` ASC 

3)那么,什么是最好的做法?两个可读的查询或一个难以阅读但快速查询?

一般规则是“可读性是直到您遇到性能问题时的要点”。仅仅因为计算资源比人力资源便宜

+0

谢谢你的回答。这似乎是将两个查询合并在一起的最简单方法。今天晚些时候我可能会标记这个最好的答案。 – AdmiralAdama

+0

我有另一组跟随这种模式的查询。你认为在SELECT语句中增加更多的子查询会更好的性能和代码明智吗?如果我重构这个另一组查询,我最终可能会在SELECT语句中产生7个子查询。所有查询的是COUNT(*)或SUM()的性质,并不会因为内部连接工作。预先感谢您的反馈。 – AdmiralAdama

+0

@AdmiralAdama在大多数情况下,我宁愿使用子查询/分组 –

在这种情况下,纯SQL比应用层(即PHP)的循环更易于维护,可读和高效。因此,考虑将汇总查询作为派生表加入(注意shift_id现在是一个分组)。现在,计数会出现与其他领域的内嵌在一个查询:

SELECT s.*, r.`race_attrition_rate`, agg.`numrows` 
FROM `shifts` s 
JOIN `races` r ON r.`race_id` = s.`race_id` 

JOIN (
     SELECT `shift_id`, COUNT(*) AS `numrows` 
     FROM `volunteer_shifts` 
     WHERE `shift_deleted` = 0 
     GROUP BY `shift_id` 
    ) AS agg 

ON agg.shift_id = s.shift_id 

WHERE r.`race_id` = '17' 
AND s.`shift_deleted` = 0 
ORDER BY s.`shift_name` ASC, s.`shift_id` ASC 

我们不知道,除非您发布表架构一个会跑得更快。 如果我是你,我可能会运行查询1,收集所有的shift_id s,然后运行1个更多的查询,使用IN拉动shift_id列表的计数。

就是这样。

SELECT COUNT(*) AS `numrows`, `shift_id` 
FROM `volunteer_shifts` 
WHERE `shift_id` IN ('42','other number', 'more numbers'...) 
AND `shift_deleted` =0 
GROUP BY `shift_id` 

如果你想要的是第二个SQL产生计数,那么这将是更具可读性,这将是这样短。

SELECT COUNT(*) numrows 
FROM shifts 
Where shift_id = 42 
    and race_id = '17' 
    and shift_deleted = 0 
+0

我编辑了我的问题,使其更清晰。第二个查询处于第一个查询结果的循环中。第一个查询中的每个结果都需要一个COUNT(*)。 – AdmiralAdama