php - 尝试消除 MYSQL 临时表,并在可能的情况下将流程合并到一条语句中

标签 php mysql performance temp-tables

我有一个应用程序正在跟踪 11 名销售员的销售情况。这是一个足够简单的过程,只不过销售可以在销售人员之间共享,从而使销售值(value)减少一半。这意味着,如果两名推销员分担一份值(value) 100 美元的工作,那么每个推销员只能为自己计算 50 美元的销售值(value)。下面是我目前用来完成此过程的代码,但它看起来很笨重,而且性能对我来说有点迟缓。是否可以将其合并到一个进程中并消除对临时表的需要(我还看到在生产中不应该使用临时表)

$sql = "DROP TEMPORARY TABLE IF EXISTS newbalancetbl" ;
  mysqli_query ($db, $sql ) or ( "Error " . mysqli_error () ) ;

  $newBalances = "
    CREATE TEMPORARY TABLE newbalancetbl (
      `custid` int NOT NULL,
      `assigned` int NOT NULL,
      `newBalance` double,
      PRIMARY KEY(custid)
    )
  ";

   mysqli_query($db, $newBalances) or die ("Sql error : ".mysqli_error());

  $year = date("Y");
  $start = "01/01/".$year;
  $today = date("Y-m-d");
  $first = $year."-01-01";

  $assignments = "SELECT leadid, price
                  FROM jobbooktbl 
                  WHERE convertdate >= '".$first."' AND convertdate<='".$today."' AND (status=4 OR status=6 OR status=7 OR status=8 OR status=11)";
  $assignmentsqry = mysqli_query($db,$assignments);
  while ($row = mysqli_fetch_array($assignmentsqry)) {
    $custid = $row["leadid"];
    $price = $row["price"];

    $statement = $db->prepare("INSERT INTO newbalancetbl (custid, newBalance) VALUES (?,?)");
    $statement->bind_param('id', $custid, $price);
    $statement->execute();
  }

  $sqlnewbal = "SELECT a.custid, COUNT(a.custid) AS assCnt
                  FROM assignmentstbl a, newbalancetbl b
                  WHERE a.custid=b.custid
                  GROUP BY a.custid";
  $qrynewbal = mysqli_query($db,$sqlnewbal);
  while ($row = mysqli_fetch_array($qrynewbal)) {
    $custid = $row['custid'];
    // $paid = $row["sumAmnt"];
    $assigned = $row['assCnt'];

    $usqlUpdate = $db->prepare("UPDATE newbalancetbl SET assigned=? WHERE custid=?");
    $usqlUpdate->bind_param('ii',$assigned,$custid);
    $usqlUpdate->execute();
  }

  $sqlnewbal = "SELECT *
                  FROM newbalancetbl";
  $qrynewbal = mysqli_query($db,$sqlnewbal);
  while ($row = mysqli_fetch_array($qrynewbal)) {
    $custid = $row['custid'];
    $assigned = $row['assigned'];
    $newBalance = $row['newBalance'];
    $newBal = $newBalance/$assigned;
    $newBal - number_format($newBal,2);

    $usqlUpdate = $db->prepare("UPDATE newbalancetbl SET newBalance=? WHERE custid=?");
    $usqlUpdate->bind_param('di',$newBal,$custid);
    $usqlUpdate->execute();
  }

  $salesArray = [];

  $tesql = "SELECT SUM(n.newBalance) AS newB, u.username
            FROM newbalancetbl n
            INNER JOIN assignmentstbl a 
              ON a.custid=n.custid 
            INNER JOIN usertbl u 
              ON a.userid=u.userid 
            -- WHERE u.salesman=1
            GROUP BY a.userid
            ORDER BY newB DESC";
  $teresult = mysqli_query($db,$tesql);
  while ($row = mysqli_fetch_array($teresult)) {
    $user = $row['username'];
    $sales = $row['newB'];

    array_push($salesArray, [$user,floatval($sales)]);
  }

  $arrayCount = count($salesArray);

  $total_sales = 0;
  $total_sales = array_sum( array_map(function($element){
                  return $element[1];
                }, 
             $salesArray));
  $pretotal_sales = number_format($total_sales, 2);
  $total_sales = '$' . number_format($total_sales, 2);

表架构:

工作簿tbl enter image description here

作业tbl enter image description here

最佳答案

我将仔细检查代码以了解其作用,并提出修改建议。

CREATE TEMPORARY TABLE newbalancetbl (
  custid     int NOT NULL,
  assigned   int NOT NULL,
  newBalance double,
  PRIMARY KEY(custid)
) ENGINE=Memory

好的。该表看起来很小,因此您可能需要使用 ENGINE=Memory 来使其更快。另外,请考虑使用 DECIMAL 类型而不是 DOUBLE。这不是强制性的,但它可以避免令人头痛的舍入误差。

无论如何。您的第一个查询。使用 php while() 循环填充表很慢而且没有必要。只需执行以下操作:

INSERT INTO newbalancetbl (custid, newBalance)
SELECT leadid, price
FROM jobbooktbl 
WHERE convertdate BETWEEN '$first' AND '$today' 
AND status IN (4,6,7,8,11);

注意 IN() 的使用,它更具可读性。另外,之间。 INSERT INTO SELECT 比在 php 中循环查询结果要快得多。另外,我在插入的列中没有看到“已分配”和“newBalance”,但该表没有指定任何默认值。您应该明确默认值。

现在,下一个查询是:

SELECT custid, COUNT(*) AS assCnt
FROM assignmentstbl a JOIN newbalancetbl b USING (custid)
GROUP BY custid

我用正确的语法改变了丑陋的旧 JOIN 语法(大约从 1999 年开始)。另外,COUNT(col) 计算“col”不为空的行。因此 COUNT(a.custid) 意味着“a.custid”实际上可以为 null。因为它不能,所以这种语法很令人困惑。我用 count(*) 替换它。

然后您查看 PHP 中的结果,并执行“UPDATE newbalancetbl SETsigned=$assCnt WHERE custid=?”

您应该决定是使用名称“assCnt”还是“assigned”。我更喜欢第一个,因为它是一个计数,名称中包含“cnt”可以减少混淆。现在,这个循环是不必要的,我们可以使用带有 JOIN 的单个 UPDATE,或者更好的是,从一开始就将值构建到 rable 中。因此,第一个查询变为:

INSERT INTO newbalancetbl (custid, newBalance, assigned)
SELECT j.leadid, j.price, 
    (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS assigned
FROM jobbooktbl j
WHERE j.convertdate BETWEEN '$first' AND '$today' 
AND j.status IN (4,6,7,8,11);

我使用了子选择。请随意使用 JOIN 来代替。

下一个查询。我将忽略“$newBal - number_format($newBal,2);”因为您使用“-”而不是“=”,所以什么也不做...这可以通过使用数字格式来解决,或者只使用这个:

UPDATE newbalancetbl 
SET newBalance=ROUND(newBalance/assigned, 2)

另一个 php 循环被消除。但我们可以消除更新,也可以消除临时表。

SELECT 
    j.leadid AS custid, 
    ROUND( j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid), 2) AS newBalance
FROM jobbooktbl j
WHERE j.convertdate BETWEEN '$first' AND '$today' 
AND j.status IN (4,6,7,8,11);

这应该给出与临时表包含的结果完全相同的结果,减去“分配”列,该列无论如何都不会在代码的其余部分中使用,因此我们可以删除它。现在,让我们将其插入到下一个查询中...

SELECT ROUND(SUM(n.newBalance), 2) AS newB, u.username
FROM (
    SELECT 
        j.leadid AS custid, 
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    WHERE j.convertdate BETWEEN '$first' AND '$today' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    -- WHERE u.salesman=1
    GROUP BY a.userid
    ORDER BY newB DESC

这应该可以满足您的要求。我在外部查询中移动了 ROUND。

关于php - 尝试消除 MYSQL 临时表,并在可能的情况下将流程合并到一条语句中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45415625/

相关文章:

MySQL-WHERE 子句在此处的相关子查询中的作用是什么

mysql - 搜索数据库中是否存在多个对象

reactjs - 在 React 组件中使用展开语法时顺序重要吗?

java - 有没有办法用 PHP 或 Java 检查 GIF 图像是否有动画?

php - Mysql结果限制输出

php - 我可以让 xdebug 停止\中断异常吗? (Ubuntu/Netbeans IDE/PHP 5.4/CLI/xdebug)

mysql - 不明确的列名称 laravel 5.3

javascript - react : how to pass arguments to the callback

sql - 为什么加入需要花费大量时间来执行?

php - VScode PHPCS 扩展错误 : Referenced Sniff "WordPress-Core" does not exist