3

我一直在编写一个新仪表板,我想在其中显示各种数据库统计信息,主要是计算行数并将结果设置为变量,它们都可以正常工作,但我有点担心如果有这么多 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);
}

非常感谢!

4

6 回答 6

2

我会确保您有适当的索引(如果您愿意,可以使用索引)。

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

SELECT * FROM $tbl_players WHERE Console = 'XBOX360'

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

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

...然后将正确的 PHP 放在适当的位置以仅检索计数。

于 2013-01-22T22:37:25.617 回答
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"];
}

跟进:

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

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"] ;
于 2013-01-22T22:51:18.620 回答
0

您正在向服务器发送 9 个请求,这需要 9 次往返。为什么不只使用UNION ALL单个请求?对您的程序知之甚少,可以肯定地说您可能需要考虑重新设计。

于 2013-01-22T22:38:15.680 回答
0

根据表中的内容,您可以使用聚合查询来获取所需的信息。

SELECT COUNT(*) `total`, Console, fathread 
FROM $tbl_players
GROUP BY Console, fathread
于 2013-01-22T22:38:56.727 回答
0

由于您只是计算每个类别中的条目数,因此您可以使用COUNTand消除大部分查询GROUP 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循环。

于 2013-01-22T22:46:09.403 回答
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 中试一试,看看它是如何工作的。

于 2013-01-22T22:53:33.917 回答