SQL多个查询 - 太重了?

时间:2013-01-22 22:34:24

标签: php mysql

我一直在编写一个新的仪表板,我想显示各种数据库统计信息,主要是计算行数并将结果设置为变量,它们都正常工作,但是我有点担心这么多的SELECT查询也会变得太多如果很多用户正在进入或刷新页面,那就很重要。

感谢您的意见:)

$tbl_players = players;

$xbox = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'XBOX360'");
$ps3 = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PS3'");
$pc = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PC'");
$xbfa = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'XBOX360' && fathread LIKE 'http%'");
$psfa = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PS3' && fathread LIKE 'http%'");
$pfa = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PC' && fathread LIKE 'http%'");
$xbcr = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'XBOX360' && crthread LIKE 'http%'");
$pscr = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PS3' && crthread LIKE 'http%'");
$pcr = mysql_query("SELECT * FROM $tbl_players WHERE Console = 'PC' && crthread LIKE 'http%'");
while($row = mysql_fetch_array($xbox))
    {
$cxbox = mysql_num_rows($xbox);
}
while($row = mysql_fetch_array($ps3))
    {
$cps3 = mysql_num_rows($ps3);
}
while($row = mysql_fetch_array($pc))
    {
$cpc = mysql_num_rows($pc);
}
while($row = mysql_fetch_array($xbfa))
    {
$xboxfa = mysql_num_rows($xbfa);
}
while($row = mysql_fetch_array($psfa))
    {
$ps3fa = mysql_num_rows($psfa);
}
while($row = mysql_fetch_array($pfa))
    {
$pcfa = mysql_num_rows($pfa);
}
while($row = mysql_fetch_array($xbcr))
    {
$xboxcr = mysql_num_rows($xbcr);
}
while($row = mysql_fetch_array($pscr))
    {
$ps3cr = mysql_num_rows($pscr);
}
while($row = mysql_fetch_array($pcr))
    {
$pccr = mysql_num_rows($pcr);
}

$tbl_interactive = interactive;

$maximum = mysql_query("SELECT ID FROM $tbl_interactive ORDER BY ID DESC LIMIT 1");
while($max = mysql_fetch_array($maximum))
{
$cint = $max['ID'];
}
$xboxf = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'XBOX360' && Type = 'Player' && $date < EndTime");
$xboxc = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'XBOX360' && Type = 'Club' && $date < EndTime");
$ps3f = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'PS3' && Type = 'Player' && $date < EndTime");
$ps3c = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'PS3' && Type = 'Club' && $date < EndTime");
$pcf = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'PC' && Type = 'Player' && $date < EndTime");
$pcc = mysql_query("SELECT * FROM $tbl_interactive WHERE Console = 'PC' && Type = 'Club' && $date < EndTime");
while($row = mysql_fetch_array($xboxf))
    {
$xboxfi = mysql_num_rows($xboxf);
}
while($row = mysql_fetch_array($xboxc))
    {
$xboxci = mysql_num_rows($xboxc);
}
while($row = mysql_fetch_array($ps3f))
    {
$ps3fi = mysql_num_rows($ps3f);
}
while($row = mysql_fetch_array($ps3c))
    {
$ps3ci = mysql_num_rows($ps3c);
}
while($row = mysql_fetch_array($pcf))
    {
$pcfi = mysql_num_rows($pcf);
}
while($row = mysql_fetch_array($pcc))
    {
$pcci = mysql_num_rows($pcc);
}

非常感谢!

6 个答案:

答案 0 :(得分:3)

我会确保你有适当的指数(索引,如果你愿意)。

此外,您可能希望使用COUNT而不是选择大量行,然后仅使用行计数。这是因为像这样的查询:

SELECT * FROM $tbl_players WHERE Console = 'XBOX360'

...正在发送大量数据,由于您没有使用它,这浪费了带宽和不必要的额外加载时间。最好配合:

SELECT COUNT(*) FROM $tbl_players WHERE Console = 'XBOX360'

...然后使用适当的PHP来检索计数。

答案 1 :(得分:1)

是的,这是太多的查询,太多的开销,以及太多繁重的工作来获得你想要的结果集。

您可以使用单个语句从$tbl_players表中获取所有这九个计数,并在一行中。您拥有的这九个单独的语句正在准备九个单独的结果集,并且您将结果集中的所有这些行提取给客户端以获取计数。 (也许在那里有一些优化,但是MySQL正在准备所有那些行返回到客户端。)让MySQL只返回你想要的计数会更有效率,使用类似这样的语句:

SELECT SUM(IF(p.Console = 'XBOX360' ,1,0))                             AS xbox
     , SUM(IF(p.Console = 'PS3'     ,1,0))                             AS ps3
     , SUM(IF(p.Console = 'PC'      ,1,0))                             AS pc
     , SUM(IF(p.Console = 'XBOX360' AND p.fathread LIKE 'http%' ,1,0)) AS xbfa
     , SUM(IF(p.Console = 'PS3'     AND p.fathread LIKE 'http%' ,1,0)) AS psfa
     , SUM(IF(p.Console = 'PC'      AND p.fathread LIKE 'http%' ,1,0)) AS pfa
     , SUM(IF(p.Console = 'XBOX360' AND p.crthread LIKE 'http%' ,1,0)) AS xbfr
     , SUM(IF(p.Console = 'PS3'     AND p.crthread LIKE 'http%' ,1,0)) AS pscr
     , SUM(IF(p.Console = 'PC'      AND p.crthread LIKE 'http%' ,1,0)) AS pcr
  FROM $tbl_players p

这会让你回到一行,有九个值。这将大大减少您获得的代码量,并显着提高性能。

同样,您也可以使用单个语句从$tbl_interactive表中获取所有这些计数:

SELECT SUM(IF(t.Console = 'XBOX360' AND t.Type = 'Player' ,1,0)) AS xbfi
     , SUM(IF(t.Console = 'XBOX360' AND t.Type = 'Club'   ,1,0)) AS xbci
     , SUM(IF(t.Console = 'PS3'     AND t.Type = 'Player' ,1,0)) AS psfi
     , SUM(IF(t.Console = 'PS3'     AND t.Type = 'Club'   ,1,0)) AS psci
     , SUM(IF(t.Console = 'PC'      AND t.Type = 'Player' ,1,0)) AS pcfi
     , SUM(IF(t.Console = 'PC'      AND t.Type = 'Club'   ,1,0)) AS pcci
  FROM $tbl_interactive t
 WHERE t.Console IN ('XBOX360','PS3','PC')
   AND t.Type IN ('Player','Club')
   AND $date < t.EndTime

while($row = mysql_fetch_array($tbl_interactive_counts))
{
    $xboxfi = $row["xbfi"];
    $xboxci = $row["xbci"];
    $ps3fi  = $row["psfi"];
    $ps3ci  = $row["psci"];
    $pcfi   = $row["pcfi"];
    $pcci   = $row["pcci"];
}

随访:

当没有满足谓词的行(即匹配WHERE子句)时,上面的SQL语句可能返回NULL而不是零。要使语句返回零计数而不是NULL,我们可以使用MySQL IFNULL()函数作为方便的简写:

SELECT IFNULL(SUM(IF(t.Console = 'XBOX360' AND t.Type = 'Player' ,1,0)),0) AS xbfi
     , IFNULL(SUM(IF(t.Console = 'XBOX360' AND t.Type = 'Club'   ,1,0)),0) AS xbci
     , IFNULL(SUM(IF(t.Console = 'PS3'     AND t.Type = 'Player' ,1,0)),0) AS psfi
     , IFNULL(SUM(IF(t.Console = 'PS3'     AND t.Type = 'Club'   ,1,0)),0) AS psci
     , IFNULL(SUM(IF(t.Console = 'PC'      AND t.Type = 'Player' ,1,0)),0) AS pcfi
     , IFNULL(SUM(IF(t.Console = 'PC'      AND t.Type = 'Club'   ,1,0)),0) AS pcci
  FROM $tbl_interactive t
 WHERE t.Console IN ('XBOX360','PS3','PC')
   AND t.Type IN ('Player','Club')
   AND $date < t.EndTime

请注意,我们刚刚包装了一个表达式:IFNULL(expr,0)

这只是一个等同于:IF(expr IS NULL, 0, expr)

的简写

也等同于ANSI标准:CASE WHEN expr IS NULL THEN 0 ELSE expr END

(使用IFNULL,我们只需要指定expr一次。)


或者,你可以让MySQL返回NULL,并在PHP中用零处理NULL的替换。 (请注意,$row数组中的获取值仍将包含NULL,但将为标量指定零:

$xboxfi = is_null($row["xbfi"]) ? 0 : $row["xbfi"] ;

答案 2 :(得分:0)

您向服务器发送了9个请求,需要9次往返。为什么不使用单个UNION ALL和单个请求?对你的程序了解不够,可以肯定地说你可能想考虑一些重新设计。

答案 3 :(得分:0)

根据您在表格中的内容,您可以使用汇总查询来获取所需信息。

SELECT COUNT(*) `total`, Console, fathread 
FROM $tbl_players
GROUP BY Console, fathread

答案 4 :(得分:0)

由于您只计算每个类别中的条目数,因此您可以使用COUNTGROUP BY来消除大多数查询。一个例子:

$tbl_players_result = mysql_query("SELECT Console, COUNT(*) AS item_count FROM $tbl_players GROUP BY Console");
while($row = mysql_fetch_assoc($tbl_players_result))
{
    /* Testing... */
    print($row["Console"] . " - " . $row["item_count"] . " items");
}

对于具有附加条件的查询(fathread,crthread),您可以执行相同的操作。

此外,您只需为每个结果调用mysql_num_rows一次,因此您也不需要这些while循环。

答案 5 :(得分:0)

许多CMS系统和在线商店在一次刷新时运行50个或更多查询。

无论如何 - 在你的情况下 - 我看到了一些优化的可能性。例如 - 您可以在一个查询中读取有关许多类型和控制台的信息,然后在PHP中处理/过滤返回的数据。也许你应该在PHP(数组,结果获取,foreach循环)和一些MySQL训练中进行一些简单和中等的练习。它会帮助你很多。我认为大多数节省时间的教育材料都是The New BostonPHP Academy。有许多有价值的视频教程。

我不会给你完整的解决方案(这可能需要花费太多时间),我不确定你的查询的最终目的是什么,但你可以从将它们合并到一个查询开始。

也许是这样的?

SELECT * FROM $tbl_interactive 
WHERE 
    Console IN('XBOX360', 'PS3', 'PC') && 
    Type in('Player','Club') && 
    $date < EndTime

如果您只想获得行数 - 您不应该使用*并在PHP中计算结果集行数。

使用一个字段或计数(*)函数。在某些字段上添加GROUP BY,并将这些字段添加到结果中(在计数之前或之前)会将您的计数结果划分为包含少量选项的几行,并为您的组添加行数。

以身作则计数和分组:

SELECT Type, Console, count(*) FROM $tbl_interactive 
WHERE 
    Console IN('XBOX360', 'PS3', 'PC') && 
    Type in('Player','Club') && 
    $date < EndTime
GROUP BY Type, Console

当然你必须阅读结果集,而不是返回的行数。

在MySQL工作台或phpmyadmin中尝试查看它是如何工作的。