【问题标题】:How I do optimize a slow query caused by a large dataset?如何优化由大型数据集引起的慢查询?
【发布时间】:2013-03-15 01:55:13
【问题描述】:

我提取了很多信息,结果我的页面在大约 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、project:varchar(50)、feature:varchar(50)、里程碑:varchar(50)、QAAssignedTo:varchar(50)、ValidationAssignedTo:varchar(50)、Priority:varchar(50 ), groupId:int

【问题讨论】:

  • 你的表是如何被索引的?
  • 使用 JOIN 组合您的两个查询。
  • 您需要向我们展示表和索引定义。 诊断慢查询需要完整的表和索引定义,而不仅仅是描述或解释。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。如果您知道如何处理EXPLAIN 或获取执行计划,请将结果也放入问题中。
  • 您应该考虑使用 SQL 连接。您对数据库进行了太多调用。如果您有 5 个源和 7 个目标,那么您将对数据库进行 35 次 SELECT 查询。如果您使用的是 JOIN,那么您将进行一次 SELECT 查询。

标签: php sql optimization


【解决方案1】:

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

运行嵌套循环不利于性能。在这样的嵌套循环中运行查询是导致性能非常差的一个秘诀。在 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.

【讨论】:

  • 刚刚更改了 SELECT * 以选择特定列。那是我本来打算做的,但忘记了。我会试一试 JOIN,看起来肯定会有很大帮助。还添加了有关我的表格外观的信息。
  • 为什么我们需要检查 $last_dest?
  • 因为您想在“目标项目:”标题更改时输出它。
【解决方案2】:

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

【讨论】:

    【解决方案3】:
    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

    【讨论】:

    • 不幸的是,我只能通过只读帐户访问数据库。我需要提取这 3 个表中的所有行。我在我的 PHP 逻辑中做的一些愚蠢的事情我可以改进吗?
    • 第 2 步你仍然可以,所以从表中选择 colA、colB、colC 而不是从表中选择 *。此外,您还可以查看缓冲对性能的影响:sitepoint.com/forums/…
    • 我刚刚更新以选择特定的列。我来看看缓冲。
    【解决方案4】:

    我假设 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 来确定正确的目的地。取决于你正在做什么,它应该会节省一些时间。

    【讨论】:

      【解决方案5】:

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

      有jquery方法可以增加显示的记录数而无需返回服务器。

      【讨论】:

        【解决方案6】:

        对于初学者,您可能希望减少运行的查询数量。例如,执行一个查询,遍历这些结果并运行另一个查询,然后遍历该结果集运行更多查询通常被认为是不好的。运行的查询数量呈指数级增长。

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

        使用连接对所有表执行单个查询并遍历单个结果。

        【讨论】:

          猜你喜欢
          • 2017-09-18
          • 2017-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-22
          • 2018-03-07
          • 2019-11-21
          • 1970-01-01
          相关资源
          最近更新 更多