我如何优化由大型数据集引起的慢查询?

时间:2013-03-14 17:21:52

标签: php sql optimization

我已经撤回了大量信息,因此,我的页面加载时间约为22~24秒。我可以做些什么来优化我的代码?

这是我的代码:

<?php
$result_rules = $db->query("SELECT source_id, destination_id FROM dbo.rules");

while($row_rules = sqlsrv_fetch_array($result_rules)){
$result_destination = $db->query("SELECT pk_id, project FROM dbo.destination WHERE pk_id=" . $row_rules['destination_id'] . " ORDER by project ASC");
    while($row_destination = sqlsrv_fetch_array($result_destination)){
        echo "Destination project: ";
        echo "<span class='item'>".$row_destination['project']."</span>";
        echo "ID: ".$row_rules['destination_id']."<br>";
        if ($row_rules['source_id'] == null) {
            echo "Source ID for Destination ID".$row_rules['destination_id']." is NULL<br>";
        } else {
            $result_source = $db->query("SELECT pk_id, project FROM dbo.source WHERE pk_id=" . $row_rules['source_id'] . " ORDER by project ASC");
            while($row_source = sqlsrv_fetch_array($result_source)){    
                echo "Source project: ";
                echo $row_source['project'];
                echo " ID: ".$row_rules['source_id']."<br>";
            }
        }
    }
}
?>

这是我的表格的样子:

源表:pk_id:int,project:varchar(50),feature:varchar(50),milestone:varchar(50),reviewGroup:varchar(125),groupId:int

规则表:pk_id:int,source_id:int,destination_id:int,login:varchar(50),status:varchar(50),batchId:int,srcPGroupId:int,dstPGroupId:int

目标表:pk_id:int,项目:varchar(50),feature:varchar(50),milestone:varchar(50),QAAssignedTo:varchar(50),ValidationAssignedTo:varchar(50),Priority:varchar(50) ),groupId:int

6 个答案:

答案 0 :(得分:0)

(pk_id, project)上添加索引,使其包含对查询重要的所有字段。

答案 1 :(得分:0)

  1. 确保将pk_Id编入索引:http://www.w3schools.com/sql/sql_create_index.asp

  2. 除了使用select *之外,不返回所需的列,除非您需要所有列。

  3. 我还建议将SQL代码移到服务器并调用存储过程。

  4. 如果你的后端是mysql,你可以考虑使用LIMIT:http://php.about.com/od/mysqlcommands/g/Limit_sql.htm

答案 2 :(得分:0)

我假设else子句正在减慢你的代码。我建议在开始时保存您将需要的所有数据,然后在else子句中再次访问该数组。基本上,您不需要每次都运行它。

$result_destination = $db->query("SELECT * FROM dbo.destination WHERE pk_id=" . $row_rules['destination_id'] . " ORDER by project ASC")

您可以提前获取数据并使用PHP迭代它。

$result_destinations = $db->query("SELECT * FROM dbo.destination ORDER by project ASC")

然后在您的代码中使用PHP来确定正确的目标。根据你正在做的事情,它应该节省一些时间。

答案 3 :(得分:0)

对于初学者,您可能希望降低运行的查询数量。例如,执行查询,循环遍历这些结果并运行另一个查询,然后循环遍历运行更多查询的结果集通常被认为是错误的。运行的查询数量呈指数增长。

例如,如果您从第一个查询返回100行,并从每个子查询返回10行。第一个查询返回您循环的100行。对于您再次查询的每一个。您现在有101个查询。然后,对于这100个中的每一个,您运行另一个查询,每个返回10行。您现在处于1001个查询。每个查询都必须将数据发送到服务器(查询文本),等待响应并获取数据。这需要很长时间。

使用连接对所有表执行单个查询,并循环显示单个结果。

答案 4 :(得分:0)

另一个考虑因素是浏览器渲染php代码生成的html所需的时间。您呈现的数据越多,所需的时间就越长。根据受众的要求,您可能希望一次只显示x条记录。

有jquery方法可以在不返回服务器的情况下增加显示的记录数。

答案 5 :(得分:0)

如果您需要有关优化查询的帮助,请提供架构详细信息和解释计划的输出。

运行嵌套循环对性能不利。在这样的嵌套循环中运行查询是非常差的性能的一个配方。在select中使用'*'也不利于性能(特别是你只使用几列)。

您应该首先优化PHP并合并查询:

$result_rules = $db->query(
     "SELECT rule.destination_id, [whatever fields you need from dbo.rules] 
             dest.project AS dest_project,
             src.project AS src_project,
             src.pk_id as src_id
      FROM dbo.rules rule
      INNER JOIN dbo.destination dest
          ON dest.pk_id=rule.destination_id
      LEFT JOIN dbo.source src
          ON src.pk_id=rule.source_id
      ORDER BY rule.destination_id, dest.project, src.project");

$last_dest=false;
$last_src=false;
while($rows = sqlsrv_fetch_array($result)){  
    if ($row['destination_id']!==$last_dest) {
       echo "Destination project: ";
       echo "<span class='item'>".$row['dest_project']."</span>";
       echo "ID: ".$row['destination_id']."<br>";
       $last_dest=$row['destination_id'];
    }
    if (null===$row['src_id']) {
       ... I'll let you sort out the rest.